﻿Imports System.IO
Imports System.Reflection


Public Class Form1
    Shared MyMidi
    Shared jsxOutputfile
    Shared keys() = {"c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"}
    Shared fi As Long = 0
    Shared fc As Byte()
    Shared totalDtime As Long = 0
    Shared Dtime As Long = 0
    Shared DPQN As Double = 480
    Shared CurrentChunk As String = ""
    Shared CurrentTrackName As String = ""
    Shared CurrentTrackNum As Integer = 0
    Shared CurrentInstrumentName As String = ""
    Shared CurrentController As Integer = 0
    Shared controllers() = {"Bank Select", "Modulation wheel", "Breath control", "Undefined", "Foot controller", "Portamento time", _
"Data Entry", "Channel Volume (formerly Main Volume)", "Balance", "Undefined", "Pan", "Expression Controller", _
"Effect control 1", "Effect control 2", "Undefined", "Undefined", "General Purpose Controller #1", _
"General Purpose Controller #2", "General Purpose Controller #3", "General Purpose Controller #4", "Undefined", _
"Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", _
"Undefined", "Undefined", "Bank Select", "Modulation wheel", "Breath control", "Undefined", "Foot controller", _
"Portamento time", "Data entry", "Channel Volume (formerly Main Volume)", "Balance", "Undefined", "Pan", "Expression Controller", _
"Effect control 1", "Effect control 2", "Undefined", "Undefined", "General Purpose Controller #1", _
"General Purpose Controller #2", "General Purpose Controller #3", "General Purpose Controller #4", "Undefined", _
"Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", _
"Undefined", "Undefined", "Damper pedal on/off (Sustain)", "Portamento on/off", "Sustenuto on/off", "Soft pedal on/off", _
"Legato Footswitch", "Hold 2", "Sound Controller 1 (Sound Variation)", "Sound Controller 2 (Timbre)", _
"Sound Controller 3 (Release Time)", "Sound Controller 4 (Attack Time)", "Sound Controller 5 (Brightness)", "Sound Controller 6", _
"Sound Controller 7", "Sound Controller 8", "Sound Controller 9", "Sound Controller 10", "General Purpose Controller #5", "General Purpose Controller #6", _
"General Purpose Controller #7", "General Purpose Controller #8", "Portamento Control", "Undefined", "Undefined", "Undefined", "Undefined", _
"Undefined", "Undefined", "Effects 1 Depth", "Effects 2 Depth", "Effects 3 Depth", "Effects 4 Depth", "Effects 5 Depth", "Data entry +1", _
"Data entry -1", "Non-Registered Parameter Number LSB", "Non-Registered Parameter Number MSB", "Registered Parameter Number LSB", _
"Registered Parameter Number MSB", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", _
"Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "All Sound Off", _
"Reset All Controllers", "Local control on/off", "All notes off", "Omni mode off (+ all notes off)", "Omni mode on (+ all notes off)", _
"Poly mode on/off (+ all notes off)", "Poly mode on (incl mono=off +all notes off)"}
    Shared controllerIND(128) As Integer
    Shared MetaCommands(128) As String
    Shared MetaIND(128) As Integer
    Shared BaseCommands() = {"Note Off", "Note On", "Key Aftertouch", "Controller", "Program Change", "Channel_AfterTouch", "Pitch Wheel", "Normal Sysex"}
    Shared BaseCommand
    Shared BaseIND(128) As Integer
    Shared currentTempo As Double
    Shared TicksInClick = 24
    Shared BeatsPassed As Double = 0
    Shared tempos(2000, 2) As Double
    Shared temposCount = 0
    Shared currentTempoIndex = 0
    Shared previousTempoIndex = 0
    Shared BPM As Double = 120
    Shared SecsInEvent As Double
    Shared SecsInTrack As Double
    Shared lookup128() As Long = {1, 128, 16384, 2097152, 268435456, 34359738368}
    Shared MyOutputfile As String = ""
    Shared HightestTrackTime As Double = 0
    Shared TotalBeatsPassed As Double = 0
    Shared MyFile As String
    'Shared MyOutputFile As String
    Shared ShortestNote As Double = 10000000
        
    Shared MIDIevents As MIDIeventCollection = New MIDIeventCollection()
    Shared RME As MIDIevent
    ' FolderBrowserDialog1.ShowDialog()
    'Dim a As String = FolderBrowserDialog1.SelectedPath
    'MsgBox(a)



    Private Sub ReadMidiFile()
        MIDIevents.Clear()

        Dim n As Integer
        Dim MostRecentCommand As Integer
        'ListBox2.Items.Clear()
        CheckedListBox1.Items.Clear()
        CheckedListBox2.Items.Clear()
        'CheckedListBox3.Items.Clear()

        Dim nn As Long = 1
        Dim tn As Integer = 0
        Dim ttemp = ""
        Dim ttempi As Long = 0
        Dim ttempi2 As Long = 0
        Dim ttempi3 As Integer = 0
        Dim tempnote = 0
        Dim tempvelocity = 0
        tempos(0, 1) = 0 : tempos(0, 2) = 120 : temposCount = 1
        CurrentTrackNum = 0
        HightestTrackTime = 0
        'Reset all IND counters
        For n = 0 To 128
            If n < 8 Then BaseIND(n) = 0
            controllerIND(n) = 0
            MetaIND(n) = 0
        Next
        Dim Metacommand As Integer = 0
        Dim MetaLength As Integer = 0
        Dim chkStart As Long = 0


        fc = My.Computer.FileSystem.ReadAllBytes(MyFile)
        Dim fileData As FileInfo = My.Computer.FileSystem.GetFileInfo(MyFile)
        ProgressBar1.Maximum = fileData.Length
        Label9.Text = fileData.Length
        fi = 0
        'CHUNKS
        While fi < fileData.Length
            CurrentChunk = (GetChunkName())
            ' MsgBox(CurrentChunk)
            ttempi = GetChunkSize()
            ''*'ListBox1.Items.Add("0,0,0,0,0,0,0,0,0,Chunktype & (size),-," & CurrentChunk & "(" & ttempi & ")")
            RME = New MIDIevent() : RME.me_type0 = 0 : RME.me_Event = "MidiFile Chunk (Name & Size)" : RME.me_Event2 = CurrentChunk & " " & ttempi : MIDIevents.Add(RME)

            Select Case CurrentChunk
                Case "MThd"
                    '  "MThd" Then "Valid midifile heading: "
                    ttempi = GetWord()
                    RME = New MIDIevent() : RME.me_type0 = 0 : RME.me_Event = "MidiFile format" : RME.me_Event2 = ttempi : MIDIevents.Add(RME)
                    ttempi = GetWord()
                    RME = New MIDIevent() : RME.me_type0 = 0 : RME.me_Event = "MidiFile Number of Tracks" : RME.me_Event2 = ttempi : MIDIevents.Add(RME)
                    DPQN = GetWord()
                    RME = New MIDIevent() : RME.me_type0 = 0 : RME.me_Event = "MidiFile DPQN" : RME.me_Event2 = DPQN : MIDIevents.Add(RME)
                Case "MTrk"
                    'a TRACK chunk
                    CurrentTrackNum = CurrentTrackNum + 1
                    CurrentTrackName = Str(CurrentTrackNum)
                    CurrentInstrumentName = ""
                    totalDtime = 0
                    TotalBeatsPassed = 0
                    currentTempoIndex = 0
                    previousTempoIndex = 0
                    currentTempo = 120
                    SecsInTrack = 0
                    chkStart = fi + ttempi

                    While fi < chkStart
                        ProgressBar1.Value = fi
                        Dtime = GetDeltaTime()
                        ''''ListBox1.Items.Add("Deltatime: " & dtime)

                        'Allow for running status where the Command does not require to be repeated
                        ttempi3 = GetNextByte()
                        If ttempi3 > 127 Then
                            ttempi2 = GetByte()
                        Else
                            ttempi2 = MostRecentCommand
                        End If
                        Metacommand = -1
                        Select Case ttempi2
                            Case 255
                                Metacommand = GetByte()
                                MetaLength = GetByte()

                                Select Case Metacommand
                                    Case 0 'Track Sequence number
                                        ttempi = GetWord()
                                        CurrentTrackName = ttempi
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttempi : MIDIevents.Add(RME)
                                    Case 1 'Text
                                        ttemp = readString(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 2 'Copyright
                                        ttemp = readString(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 3 'Track Name
                                        ttemp = readString(MetaLength)
                                        CurrentTrackName = ttemp
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 4 'Instument Name
                                        ttemp = readString(MetaLength)
                                        CurrentInstrumentName = ttemp
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 5 'Lyrics
                                        ttemp = readString(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 6 'Marker Name
                                        ttemp = readString(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 7 'Cue point
                                        ttemp = readString(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 32 'midi Channel - (now obselete according to the MMA)
                                        tn = GetByte()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Value1 = tn : MIDIevents.Add(RME)
                                    Case 33 'midi port - (now obselete according to the MMA)
                                        tn = GetByte()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Value1 = tn : MIDIevents.Add(RME)
                                    Case 47 'End of Track
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : MIDIevents.Add(RME)
                                    Case 81 'Set Tempo(BPM)
                                        ttempi = GetTempo()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttempi : MIDIevents.Add(RME)
                                    Case 84 'SMTPE(offset)
                                        ttemp = GetSMPTEoffset()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 88 'Time Signature
                                        ttemp = GetTimeSignature()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 89 'Key Signature
                                        ttemp = GetKeySignature()
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case 127 'Sequencer Specific
                                        ttemp = GetSequencerSpecx(MetaLength)
                                        RME = New MIDIevent() : RME.me_type0 = 1 : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                    Case Else
                                        MsgBox("unknown metatype: " & MetaCommands(Metacommand) & Metacommand)
                                        RME = New MIDIevent() : TimeData() : RME.me_Event = MetaCommands(Metacommand) : RME.me_Event2 = ttempi2 : MIDIevents.Add(RME)
                                        ''''ListBox1.Items.Add("Data type MetaEvent: " & ttempi2 & " MetaEvent Command: " & Metacommand & " MetaEvent length: " & MetaLength)
                                End Select
                                'ListBox1.Items.Add(MetaCommands(Metacommand))
                                If Metacommand > -1 Then MetaIND(Metacommand) = MetaIND(Metacommand) + 1
                            Case 128 To 240
                                BaseCommand = -1
                                MostRecentCommand = ttempi2
                                Select Case ttempi2
                                    Case 128 To 143 'NoteOff
                                        BaseCommand = 0
                                        RME = New MIDIevent() : RME.me_type0 = 5 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Midi_Channel = ttempi2 - 128 : RME.me_note = GetByte() : RME.me_velocity = GetByte() : MIDIevents.Add(RME)
                                    Case 144 To 159 'NoteOn
                                        BaseCommand = 1
                                        RME = New MIDIevent() : TimeData()
                                        RME.me_type0 = 2
                                        RME.me_Midi_Channel = ttempi2 - 144
                                        tempnote = GetByte()
                                        tempvelocity = GetByte()
                                            RME.me_Event = BaseCommands(BaseCommand) : RME.me_note = tempnote : RME.me_velocity = tempvelocity
                                        MIDIevents.Add(RME)
                                    Case 160 To 175 'Key_AfterTouch
                                        BaseCommand = 2
                                        RME = New MIDIevent() : RME.me_type0 = 2 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Midi_Channel = ttempi2 - 160 : RME.me_note = GetByte() : RME.me_Value1 = GetByte() : MIDIevents.Add(RME)
                                    Case 176 To 191 'CC
                                        BaseCommand = 3
                                        tn = GetByte()
                                        controllerIND(tn) = controllerIND(tn) + 1
                                        RME = New MIDIevent() : RME.me_type0 = 4 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Event2 = controllers(tn) : RME.me_Midi_Channel = ttempi2 - 176 : RME.me_Value1 = GetByte() : MIDIevents.Add(RME)
                                    Case 192 To 207 'ProgramChange
                                        BaseCommand = 4
                                        RME = New MIDIevent() : RME.me_type0 = 2 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Midi_Channel = ttempi2 - 192 : RME.me_Value1 = GetByte() : MIDIevents.Add(RME)
                                    Case 208 To 223 'Channel_AfterTouch
                                        BaseCommand = 5
                                        RME = New MIDIevent() : RME.me_type0 = 2 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Midi_Channel = ttempi2 - 208 : RME.me_Value1 = GetByte() : MIDIevents.Add(RME)
                                    Case 224 To 239 'PitchWheel
                                        BaseCommand = 6
                                        'pitchwheel channel bottom7bits, top7bits
                                        RME = New MIDIevent() : RME.me_type0 = 2 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Midi_Channel = ttempi2 - 224 : RME.me_Value1 = GetByte() : RME.me_value2 = GetByte() : MIDIevents.Add(RME)
                                    Case 240 'Normal Sysex
                                        BaseCommand = 7
                                        ttemp = GetNormalSysEx()
                                        RME = New MIDIevent() : RME.me_type0 = 2 : TimeData() : RME.me_Event = BaseCommands(BaseCommand) : RME.me_Event2 = ttemp : MIDIevents.Add(RME)
                                End Select
                                If BaseCommand > -1 Then BaseIND(BaseCommand) = BaseIND(BaseCommand) + 1
                            Case Else
                                MsgBox("Unknown data type: " & ttempi2)
                                ''*'ListBox1.Items.Add(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?? data: " & ttempi2)
                                RME = New MIDIevent() : RME.me_Event = "Unknown MIDI Event: " & ttempi2 : MIDIevents.Add(RME)

                                'Dim o
                                'For o = fi - 3 To fi + 3
                                'ListBox1.Items.Add(Str(o) & " " & fc(o) & " " & Chr(fc(o)))
                                'Next
                                'MsgBox("sorry!")

                        End Select

                    End While

                Case Else
                    MsgBox("ERROR. Unknown ChunkType:" & CurrentChunk)
                    RME = New MIDIevent() : RME.me_type0 = 0 : RME.me_Event = "Unknown Chunk & Size" & ttemp & " " & ttempi : MIDIevents.Add(RME)
                    Exit Sub
            End Select

        End While

        'Calculate the durations of Notes
        Calculate_me_mSecs_length()

        ProgressBar1.Value = 0
        InitialiseMETAnames()
        InitialiseBASEnames()
        InitialiseControllerboxes()
        Me.Text = fileData.Name ' 
        Button3.Enabled = True ' AE script can now be generated
        UpdateGeneralTab()
    End Sub


    Private Sub InitialiseControllerboxes()
        'standard key names and selection boxes
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim xx As Integer = 0
        CheckedListBox1.Items.Clear()
        For x = 0 To 127
            'If controllerIND(x) > 0 Then
            'If controllers(x) <> "Undefined" Then
            CheckedListBox1.Items.Add(controllers(x) & " (" & controllerIND(x) & ")")
            If controllerIND(x) > 0 Then
                CheckedListBox1.SetItemCheckState(x, CheckState.Checked)
                
            Else
                CheckedListBox1.SetItemCheckState(x, CheckState.Unchecked)
            End If


        Next
    End Sub
    Sub InitialiseBASEnames()
        'standard key names and selection boxes
        CheckedListBox3.Items.Clear()
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim xx As Integer = 0
        For x = 0 To UBound(BaseCommands)
            CheckedListBox3.Items.Add(BaseCommands(x) & " (" & BaseIND(x) & ")")
            If BaseIND(x) > 0 Then
                CheckedListBox3.SetItemCheckState(x, CheckState.Checked)
            Else
                CheckedListBox3.SetItemCheckState(x, CheckState.Unchecked)
            End If
        Next
    End Sub
    Private Sub cbBASE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        'get a reference to the sender objects name, and state
        Dim dtext = CStr(CType(sender, System.Windows.Forms.CheckBox).Text)
        Dim dstate = CInt(CType(sender, System.Windows.Forms.CheckBox).CheckState)
    End Sub
    Sub InitialiseMETAnames()
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim xx As Integer = 0
        CheckedListBox2.Items.Clear()
        For x = 0 To 127
            CheckedListBox2.Items.Add(MetaCommands(x) & " (" & MetaIND(x) & ")")
            If MetaIND(x) > 0 Then
                CheckedListBox2.SetItemCheckState(x, CheckState.Checked)
            Else
                CheckedListBox2.SetItemCheckState(x, CheckState.Unchecked)
            End If
        Next
    End Sub
    Public Function TimeData()
        'We know:
        'Dtime is the ticks increment since the last Event.
        'Current totalDtime
        'the previous Dtime (LastDtime)
        Dim EPstart As Long = 0
        Dim EPend As Long = 0
        Dim TickInCurrentPeriod As String = ""
        Dim NumTicks1 As String = TickInCurrentPeriod
        Dim e0 As Long = totalDtime - Dtime
        Dim e1 As Long = totalDtime
        Dim t0 As Long = 0
        Dim t1 As Long = 0
        Dim n = 0
        Dim ii As Double
        'Find the entry in the Tempo map to know the BPM at the point when this Event occurs
        previousTempoIndex = currentTempoIndex
        While (tempos(currentTempoIndex, 1) <= totalDtime) And (currentTempoIndex < (temposCount))
            currentTempo = tempos(currentTempoIndex, 2)
            currentTempoIndex = currentTempoIndex + 1
        End While

        'Find beats passed. Easily calculated, is not affected by Tempo changes.
        BeatsPassed = Dtime / DPQN

        SecsInEvent = 0
        'TickInCurrentPeriod = ""
        For n = 0 To temposCount
            t0 = CLng(tempos(n, 1))
            t1 = CLng(tempos(n + 1, 1))
            EPstart = e0
            EPend = e1
            If e0 < t0 Then EPstart = t0
            If e1 > t1 Then EPend = t1

            ii = EPend - EPstart
            If ii > 0 Then
                TickInCurrentPeriod = TickInCurrentPeriod & " (" & EPend & "-" & EPstart & "@" & n & ")"
                SecsInEvent = SecsInEvent + TicksToSecs(EPend - EPstart, n)
            End If
        Next
        NumTicks1 = TickInCurrentPeriod

        'add into the Event
        RME.me_Delta_Ticks = Dtime
        RME.me_Total_Delta_Ticks = totalDtime
        RME.me_Ticks_in_each_period = NumTicks1
        RME.me_Secs_in_Event = SecsInEvent
        RME.me_Secs_into_Track = SecsInTrack
        If SecsInTrack > HightestTrackTime Then
            HightestTrackTime = SecsInTrack
        End If
        RME.me_Current_BPM = currentTempo
        RME.me_Beats_Passed = BeatsPassed
        TotalBeatsPassed = BeatsPassed + TotalBeatsPassed
        RME.me_Total_Beats_Passed = Str(TotalBeatsPassed)
        RME.me_Trackname = CurrentTrackName
        RME.me_InstrumentName = CurrentInstrumentName

        'format a string of related values
        TimeData = "ok"
    End Function
    Function TicksToSecs(ByVal ticks As Long, ByVal tempotable As Integer)
        Dim I As Double
        If (ticks > 0) And (tempos(tempotable, 2) <> 0) Then
            I = (60 / tempos(tempotable, 2)) * (ticks / DPQN)
            SecsInTrack = SecsInTrack + I
            TicksToSecs = I
        Else
            TicksToSecs = 0
        End If
    End Function
    Function GetTempo()
        Dim i As Integer = 0
        Dim ttempi As Long = 0

        For i = 0 To 2
            ttempi = ttempi + (fc(fi + i) * (256 ^ (2 - i)))
        Next
        fi = fi + 3
        BPM = 60000000 / ttempi

        tempos(temposCount, 1) = totalDtime
        tempos(temposCount, 2) = BPM

        'Continue to build the Tempo table, where the Dtime is the same, I take the last value.
        If tempos(temposCount, 1) = tempos(temposCount - 1, 1) Then
            tempos(temposCount - 1, 2) = BPM
        Else
            temposCount = temposCount + 1
        End If

        'create an imaginary next tempo (which will get overwritten if a new Tempo appears)
        tempos(temposCount, 1) = 9999999999
        tempos(temposCount, 2) = 0

        GetTempo = ttempi
    End Function
    Function GetTimeSignature()
        TicksInClick = fc(fi + 2)
        GetTimeSignature = fc(fi) & "..." & fc(fi + 1) & "," & TicksInClick & " with 32nd notes to a quarter:" & fc(fi + 3)
        fi = fi + 4
    End Function
    Function GetNextByte()
        GetNextByte = fc(fi)
    End Function
    Function GetSMPTEoffset()
        Dim ts As String = ""
        ts = ts & CStr(GetByte()) & ":"
        ts = ts & CStr(GetByte()) & ":"
        ts = ts & CStr(GetByte()) & ":"
        ts = ts & CStr(GetByte()) & ":"
        ts = ts & CStr(GetByte()) & ":"
        GetSMPTEoffset = ts
    End Function
    Function GetByte()
        GetByte = fc(fi)
        fi = fi + 1
    End Function
    Function GetDeltaTime()
        Dim i As Integer = 0
        Dim ii As Integer = 0
        Dim ti As Integer = 0
        Dim ttempi As Long = 0

        While (fc(fi + i) > 127)
            i = i + 1
        End While

        For ii = 0 To i
            ti = fc(fi + ii)
            If ti > 127 Then ti = ti - 128
            ttempi = ttempi + (ti * (lookup128(i - ii)))
        Next

        fi = fi + i + 1
        BeatsPassed = ttempi / DPQN
        SecsInEvent = 0
        totalDtime = totalDtime + ttempi
        GetDeltaTime = ttempi
    End Function
    Function GetWord()
        Dim i As Integer = 0
        Dim ttempi As Long = 0

        For i = 0 To 1
            ttempi = ttempi + (fc(fi + i) * (256 ^ (1 - i)))
        Next
        fi = fi + 2
        GetWord = ttempi
    End Function
    Function GetChunkSize()
        Dim i As Integer
        Dim ttempi As Long = 0

        For i = 0 To 3
            ttempi = ttempi + (fc(fi + i) * (256 ^ (3 - i)))
        Next
        fi = fi + 4
        GetChunkSize = ttempi
    End Function
    Function GetChunkName()
        Dim i As Integer
        Dim ttemp As String = ""
        For i = 0 To 3
            ttemp = ttemp & Chr(fc(fi + i))
        Next
        fi = fi + 4
        GetChunkName = ttemp
    End Function
    Function GetSequencerSpecx(ByVal llen As Integer)
        Dim i As Integer
        Dim ttemp As String = ""
        'The first Data byte (or three bytes if the first byte is 0) specifies the manufacturer's ID and the following bytes contain information specified by the manufacturer   
        If fc(fi + 1) = 0 Then
            ttemp = ttemp & "ManufacturersID:" & fc(fi + 2) & " " & fc(fi + 3)
            fi = fi + 3
            llen = llen - 3
        Else
            ttemp = ttemp & "ManufacturersID:" & fc(fi + 1)
            fi = fi + 1
            llen = llen - 1
        End If

        For i = 0 To llen - 1
            ttemp = ttemp & Hex(fc(fi + i)) & " "
        Next
        fi = fi + llen
        GetSequencerSpecx = ttemp

    End Function
    Function readString(ByVal llen As Integer)
        Dim i As Integer
        Dim te As String
        Dim ttemp As String = ""
        For i = 0 To llen - 1
            te = Chr(fc(fi + i))
            If fc(fi + i) < 32 Then te = " "
            ttemp = ttemp & te
        Next
        fi = fi + llen
        readString = ttemp
    End Function
    Function GetNormalSysEx()
        'Dim i As Integer
        Dim ttemp As String = ""
        Do
            ttemp = ttemp & Hex(fc(fi)) & " "
            fi = fi + 1
        Loop Until fc(fi - 1) = 247
        GetNormalSysEx = ttemp
    End Function
    Function GetKeySignature()
        'This meta event is used to specify the key (number of sharps or flats) and scale (major or minor) of a sequence. 
        'A positive value for the key specifies the number of sharps and a negative value specifies the number of flats. 
        'A value of 0 for the scale specifies a major key and a value of 1 specifies a minor key.

        Dim i As Integer
        Dim ttemp As String = ""
        For i = 0 To 1
            ttemp = ttemp & (fc(fi + i)) & " "
        Next
        fi = fi + 2
        GetKeySignature = ttemp
    End Function
    Sub Calculate_me_mSecs_length()
        Dim nnote
        Dim nnote2
        Dim cchan
        Dim cchan2
        Dim msecs
        Dim msecs2
        Dim Index As Integer
        Dim Index2 As Integer

        ShortestNote = 1000000
        'having got all the Events into "MIDIevents", it is possible to populate the lengths of notes into me_mSecs_length
        '
        'For each Event: find any events where the Velocity=0, or it is a 'Note Off' event.
        ' then, work back and find the original 'Note On'; calculate the length; and populte the me_mSecs_length value.
        For Index = 1 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                If (MIDIevents(Index).me_velocity = 0) Or (MIDIevents(Index).me_type0 = 5) Then
                    nnote = MIDIevents(Index).me_note
                    cchan = MIDIevents(Index).me_Midi_Channel
                    msecs = MIDIevents(Index).me_Secs_into_Track

                    For n = Index - 1 To 1 Step -1
                        nnote2 = MIDIevents(n).me_note
                        cchan2 = MIDIevents(n).me_Midi_Channel
                        If (nnote = nnote2) And (cchan = cchan2) Then
                            msecs2 = MIDIevents(n).me_Secs_into_Track
                            'allow for overlapping Notes
                            If msecs <> msecs2 Then
                                MIDIevents(n).me_mSecs_length = msecs - msecs2
                            End If
                            Exit For
                        End If
                    Next
                End If

            End If
        Next



        'Find, for each NoteOn; how much ms time until the same note on that channel is played again.
        For Index = 0 To MIDIevents.Count - 1
            If (MIDIevents(Index).me_note <> "") And (MIDIevents(Index).me_type0 <> 5) Then
                nnote = MIDIevents(Index).me_note
                cchan = MIDIevents(Index).me_Midi_Channel
                msecs = MIDIevents(Index).me_Secs_into_Track
                For Index2 = Index + 1 To MIDIevents.Count - 1
                    If (MIDIevents(Index2).me_note <> "") And (MIDIevents(Index2).me_type0 <> 5) Then
                        nnote2 = MIDIevents(Index2).me_note
                        cchan2 = MIDIevents(Index2).me_Midi_Channel
                        msecs2 = MIDIevents(Index2).me_Secs_into_Track
                        If (nnote = nnote2) And (cchan = cchan2) Then
                            MIDIevents(Index).me_secs_tillnextOccurence = MIDIevents(Index2).me_Secs_into_Track - MIDIevents(Index).me_Secs_into_Track
                            ' Debug.Print(MIDIevents(Index).me_secs_tillnextOccurence)

                            Exit For
                        End If
                    End If
                Next
            End If
        Next

    End Sub
    Private Sub Form1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
        Dim files = e.Data.GetData(DataFormats.FileDrop)
        Dim f
        Dim ffilename As String = ""
        For Each f In files
            ffilename = (f)
        Next
        If InStr(LCase(ffilename), ".mid") < 1 Then
            MsgBox("Sorry. Invalid Midi file. Only MIDI can be analysed.")
        Else
            MyFile = ffilename
            Panel8.Visible = True
            ReadMidiFile()
        End If
    End Sub
    Private Sub Form1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragEnter
        e.Effect = DragDropEffects.Link
    End Sub
    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        SaveSettings()
    End Sub
    Sub LoadSettings()
        MyOutputfile = My.Settings.OutputFile
        CheckBox4.Checked = My.Settings.cb4
        CheckBox10.Checked = My.Settings.cb10
        CheckBox5.Checked = My.Settings.cb5
        CheckBox6.Checked = My.Settings.cb6
        CheckBox7.Checked = My.Settings.cb7
        CheckBox8.Checked = My.Settings.cb8
        CheckBox9.Checked = My.Settings.cb9
        CheckBox10.Checked = My.Settings.cb10
        CheckBox12.Checked = My.Settings.cb12
        CheckBox3.Checked = My.Settings.cb3
        CheckBox13.Checked = My.Settings.cb13
        CheckBox11.Checked = My.Settings.cb11
        CheckBox14.Checked = My.Settings.cb14
        CheckBox17.Checked = My.Settings.cb17
        CheckBox18.Checked = My.Settings.cb18
        CheckBox15.Checked = My.Settings.cb15
        CheckBox16.Checked = My.Settings.cb16

        CheckBox19.Checked = My.Settings.cb19
        CheckBox1.Checked = My.Settings.cb1
        CheckBox21.Checked = My.Settings.cb21
        CheckBox20.Checked = My.Settings.cb20
        CheckBox2.Checked = My.Settings.cb2

        CheckBox24.Checked = My.Settings.cb24
        CheckBox25.Checked = My.Settings.cb25
        CheckBox22.Checked = My.Settings.cb22
        CheckBox23.Checked = My.Settings.cb23
        CheckBox26.Checked = My.Settings.cb26
        CheckBox27.Checked = My.Settings.cb27
        CheckBox29.Checked = My.Settings.cb29
        If CheckBox29.Checked = False Then CheckBox19.Enabled = False
        TextBox1.Text = My.Settings.cb25fps

    End Sub
    Sub SaveSettings()
        My.Settings.cb24 = CheckBox24.Checked
        If CheckBox24.CheckState = CheckState.Checked Then
            My.Settings.OutputFile = MyOutputfile
            My.Settings.cb4 = CheckBox4.Checked
            My.Settings.cb10 = CheckBox10.Checked
            My.Settings.cb5 = CheckBox5.Checked
            My.Settings.cb6 = CheckBox6.Checked
            My.Settings.cb7 = CheckBox7.Checked
            My.Settings.cb8 = CheckBox8.Checked
            My.Settings.cb9 = CheckBox9.Checked
            My.Settings.cb10 = CheckBox10.Checked
            My.Settings.cb12 = CheckBox12.Checked
            My.Settings.cb3 = CheckBox3.Checked
            My.Settings.cb13 = CheckBox13.Checked
            My.Settings.cb11 = CheckBox11.Checked
            My.Settings.cb14 = CheckBox14.Checked
            My.Settings.cb17 = CheckBox17.Checked
            My.Settings.cb18 = CheckBox18.Checked
            My.Settings.cb15 = CheckBox15.Checked
            My.Settings.cb16 = CheckBox16.Checked

            My.Settings.cb19 = CheckBox19.Checked
            My.Settings.cb1 = CheckBox1.Checked
            My.Settings.cb21 = CheckBox21.Checked
            My.Settings.cb20 = CheckBox20.Checked
            My.Settings.cb2 = CheckBox2.Checked

            My.Settings.cb25 = CheckBox25.Checked
            My.Settings.cb22 = CheckBox22.Checked
            My.Settings.cb23 = CheckBox23.Checked
            My.Settings.cb26 = CheckBox26.Checked
            My.Settings.cb27 = CheckBox27.Checked
            My.Settings.cb29 = CheckBox29.Checked
            My.Settings.cb25fps = TextBox1.Text
        End If
    End Sub
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Panel8.Visible = False

        'CheckedListBox1.Enabled = False
        'CheckedListBox2.Enabled = False
        'CheckedListBox3.Enabled = False
        Me.Visible = True
        Me.Refresh()


        'Dim ourVersion As String
        ' If System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed Then
        'MsgBox(System.Deployment.Application.ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString)
        'MsgBox("ok")

        AboutBox1.Label18n.Text = Application.ProductName & " version " & "1.6 " & " written by "
        MetaCommands(0) = "Track Sequence number"
        MetaCommands(1) = "Text"
        MetaCommands(2) = "Copyright"
        MetaCommands(3) = "Sequence or Track name"
        MetaCommands(4) = "Track Instument name"
        MetaCommands(5) = "Lyric"
        MetaCommands(6) = "Marker"
        MetaCommands(7) = "Cue point"
        MetaCommands(8) = "Program (Patch) Name type"
        MetaCommands(9) = "Device (Port) Name"
        MetaCommands(32) = "Midi Channel - (now obselete according to the MMA)"
        MetaCommands(33) = "Midi Port - (now obselete according to the MMA)"
        MetaCommands(47) = "End of Track"
        MetaCommands(81) = "Set Tempo(BPM)"
        MetaCommands(84) = "SMTPE offset"
        MetaCommands(88) = "Time Signature"
        MetaCommands(89) = "Key Signature"
        MetaCommands(127) = "Sequencer Specific"

        'MyFile = "C:\Users\Tim\Desktop\midi2txt\midifile_EXAMPLES\SUMER_01.MID"
        '
        LoadSettings()

        ' MyFile = "C:\Users\Tim\Desktop\midi2txt\MIDI\midifleS2\beatles2.MID"
        ' If MyOutputfile = "" Then
        'MsgBox("myoutoputfile not seleced")
        'MyOutputfile = "C:\Users\Tim\Desktop\midi2txt\1b.csv"
        'End If
        ' ReadMidiFile()
        ' MsgBox("Ok")


        'Code to create a Tree of the ommands, if required.
        'Dim n As TreeNode
        'TreeView1.Nodes.Add("tim1")
        'TreeView1.Nodes.Add("tim2").Nodes.Add("3")
        'N = TreeView1.Nodes.Add("tim2").Nodes.Add("3")
        'N.nodes.Add("AddByText, Attach To Variable")
        'N.Nodes.Add("Child one")
        'N.Nodes.Add("Child two")
        'TreeView1.ExpandAll()
    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        SaveCSV()
    End Sub
    Function GetjsxOutputfile(ByVal fileType As String)
        Dim nnow As String = CStr(Now())
        nnow = Replace(nnow, "/", "_")
        nnow = Replace(nnow, ":", "_")
        nnow = Replace(nnow, " ", "__")
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)
        GetjsxOutputfile = MyOutputFolder & MyMidi & "_" & nnow & fileType



    End Function
    Function SaveScript4()
        'Create a simple file to guide another app to slide WAV files.

        'save EventID,Channel, Time of Note start, Time of Note end
        Dim nnow As String = CStr(Now())
        nnow = Replace(nnow, "/", "_")
        nnow = Replace(nnow, ":", "_")
        nnow = Replace(nnow, " ", "__")
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)
        MyOutputfile = MyOutputFolder & MyMidi & "_slicer" & nnow & ".csv"
        My.Computer.FileSystem.WriteAllText(MyOutputfile, "", False)


        'populate the values of me_mSecs_length
        Calculate_me_mSecs_length()

        Dim ttemp = ""
        Dim m As String = ""
        Dim Index As Integer




        'get the midi filename
        ' Dim a As Integer = InStrRev(MyFile, "\")
        ' Dim MyOutputFolder = MyFile.Substring(0, a)
        ' MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)

        'set the colours for each midi channel - future enhancments?
        Dim mc(16, 3) As Integer
        mc(0, 1) = 1 : mc(16, 2) = 0.5 : mc(16, 3) = 0.3
        mc(1, 1) = 1 : mc(1, 2) = 0.0 : mc(1, 3) = 0.0
        mc(2, 1) = 0 : mc(2, 2) = 1.0 : mc(2, 3) = 0.0 'green
        mc(3, 1) = 0 : mc(3, 2) = 0.0 : mc(3, 3) = 1.0
        mc(4, 1) = 0.1 : mc(4, 2) = 0.6 : mc(4, 3) = 0.8
        mc(5, 1) = 0.4 : mc(5, 2) = 1.0 : mc(5, 3) = 0.6
        mc(6, 1) = 0 : mc(6, 2) = 1.0 : mc(6, 3) = 1.0
        mc(7, 1) = 1 : mc(7, 2) = 0.0 : mc(7, 3) = 1.0
        mc(8, 1) = 0.5 : mc(8, 2) = 1.0 : mc(8, 3) = 0.0
        mc(9, 1) = 0.5 : mc(9, 2) = 0.5 : mc(9, 3) = 1.0
        mc(10, 1) = 0.5 : mc(10, 2) = 0.3 : mc(10, 3) = 0.2
        mc(11, 1) = 0.7 : mc(11, 2) = 0.2 : mc(11, 3) = 0.7
        mc(12, 1) = 0.7 : mc(12, 2) = 0.1 : mc(12, 3) = 1.0
        mc(13, 1) = 0.2 : mc(13, 2) = 0.8 : mc(13, 3) = 0.5
        mc(14, 1) = 0.2 : mc(14, 2) = 0.1 : mc(14, 3) = 0.5
        mc(15, 1) = 0.2 : mc(15, 2) = 0.2 : mc(15, 3) = 1.0
        mc(16, 1) = 0.5 : mc(16, 2) = 0.0 : mc(16, 3) = 0.0

        ''''''''''''''''''''''''''''''''''''
        Dim Vel2AE As Integer


        ProgressBar1.Maximum = MIDIevents.Count
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then

                'Find the Velocity (or a noteoff event)
                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0

                'dont need values for noteoffs, because myvalue will be the Note's actual msecs_length
                If Vel2AE <> 0 Then
                    ttemp = ""
                    ttemp = ttemp & Index & "," & MIDIevents(Index).me_Midi_Channel & "," & MIDIevents(Index).me_Secs_into_Track & "," & MIDIevents(Index).me_mSecs_length & vbCrLf
                    My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, True)
                    ' MsgBox(MIDIevents(Index).me_mSecs_length)
                End If
            End If
            ProgressBar1.Value = Index

        Next
        ' ttemp = m & ttemp & "}"
        ' My.Computer.FileSystem.WriteAllText(MyOutputfile, m & vbCrLf & "}", True)

h:

        ProgressBar1.Value = 0
        SaveScript4 = True

    End Function
    Function SaveAEscript3()
        'As used by Allegro
        'save Frame,Midichannel, Note, Velocity, Length

        MyOutputfile = GetjsxOutputfile(".jsx")
        My.Computer.FileSystem.WriteAllText(MyOutputfile, "", False)


        'populate the values of me_mSecs_length
        Calculate_me_mSecs_length()


        Dim ttemp = ""
        Dim IntResult = 0
        Dim fflag = 0
        Dim m As String = ""
        Dim xn As String = "0000"
        Dim yn As String = "0000"
        Dim Index As Integer
        Dim f As Integer
        Dim d As Integer

        'Finding out about the distribution of Notes and Channels

        Dim chanUsed(16, 4)
        ' 1= flag(is the channel used), 2=lowest Note on channel, 3=highest note on channel, 4= POINTER reference
        Dim pointerReference As Integer = 1
        For Index = 0 To 16
            chanUsed(Index, 1) = 0
            chanUsed(Index, 2) = 128
            chanUsed(Index, 3) = 0
            chanUsed(Index, 4) = 0
        Next
        'For each Event: find the highest and lowest notes for each channel;and remember which channels have actually been used.
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 2)) > CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 3)) < CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 3) = MIDIevents(Index).me_note
                End If
                chanUsed(MIDIevents(Index).me_Midi_Channel, 1) = 1
                If chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = 0 Then chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = pointerReference : pointerReference = pointerReference + 1
            End If
        Next

        'Find Highest and Lowest within all channels
        Dim HighestNote = 0
        Dim LowestNote = 127
        For Index = 0 To 16
            If chanUsed(Index, 3) > HighestNote Then HighestNote = chanUsed(Index, 3)
            If chanUsed(Index, 2) < LowestNote Then LowestNote = chanUsed(Index, 2)
        Next

        Dim UsageMap(16, 128, 2) ' 16 channels of 128 notes. 1=flag if used, 2=note order
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = 1
            End If
        Next

        For f = 0 To 16
            Index = 1
            For d = 0 To 128
                If UsageMap(f, d, 1) = 1 Then UsageMap(f, d, 2) = Index : Index = Index + 1
            Next
        Next

        'get the midi filename
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)

        'set the colours for each midi channel
        Dim mc(16, 3) As Integer
        mc(0, 1) = 1 : mc(16, 2) = 0.5 : mc(16, 3) = 0.3
        mc(1, 1) = 1 : mc(1, 2) = 0.0 : mc(1, 3) = 0.0
        mc(2, 1) = 0 : mc(2, 2) = 1.0 : mc(2, 3) = 0.0 'green
        mc(3, 1) = 0 : mc(3, 2) = 0.0 : mc(3, 3) = 1.0
        mc(4, 1) = 0.1 : mc(4, 2) = 0.6 : mc(4, 3) = 0.8
        mc(5, 1) = 0.4 : mc(5, 2) = 1.0 : mc(5, 3) = 0.6
        mc(6, 1) = 0 : mc(6, 2) = 1.0 : mc(6, 3) = 1.0
        mc(7, 1) = 1 : mc(7, 2) = 0.0 : mc(7, 3) = 1.0
        mc(8, 1) = 0.5 : mc(8, 2) = 1.0 : mc(8, 3) = 0.0
        mc(9, 1) = 0.5 : mc(9, 2) = 0.5 : mc(9, 3) = 1.0
        mc(10, 1) = 0.5 : mc(10, 2) = 0.3 : mc(10, 3) = 0.2
        mc(11, 1) = 0.7 : mc(11, 2) = 0.2 : mc(11, 3) = 0.7
        mc(12, 1) = 0.7 : mc(12, 2) = 0.1 : mc(12, 3) = 1.0
        mc(13, 1) = 0.2 : mc(13, 2) = 0.8 : mc(13, 3) = 0.5
        mc(14, 1) = 0.2 : mc(14, 2) = 0.1 : mc(14, 3) = 0.5
        mc(15, 1) = 0.2 : mc(15, 2) = 0.2 : mc(15, 3) = 1.0
        mc(16, 1) = 0.5 : mc(16, 2) = 0.0 : mc(16, 3) = 0.0

        ''''''''''''''''''''''''''''''''''''
        'scale down gracefully 20480 by 11520, div by 16 gives 1280 by 720
        Dim ScreenX = 20480
        Dim ScreenY = 11520
        Dim heightscale = Int(ScreenY / (HighestNote - LowestNote)) ' range of notes  
        Dim widthscale = Int(ScreenX / (HightestTrackTime))

        'MsgBox(HighestNote)
        '   MsgBox(LowestNote)
        'MsgBox(heightscale)
        'MsgBox(LowestNote)


        m = m & "{" & vbCrLf
        'm = m & "comp = app.project.activeItem;" & vbCrLf
        m = m & " var proj = app.project;" & vbCrLf
        m = m & "var projItems = proj.items;" & vbCrLf



        m = m & "var currentTime = new Date();" & vbCrLf
        m = m & "var hours = currentTime.getHours();" & vbCrLf
        m = m & "var minutes = currentTime.getMinutes();" & vbCrLf
        m = m & "var currentTime = new Date();" & vbCrLf
        m = m & "var month = currentTime.getMonth() + 1;" & vbCrLf
        m = m & "var day = currentTime.getDate();" & vbCrLf
        m = m & "var year = currentTime.getFullYear();" & vbCrLf
        m = m & "ctime=""" + MyMidi + " "" + hours + "":"" + minutes + "" "" +month + ""/"" + day + ""/"" + year;" & vbCrLf

        m = m & "var comp = projItems.addComp(ctime," & ScreenX & "," & ScreenY & ", 1, 5, 30);" & vbCrLf
        '  m = m & "comp.duration=" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
        m = m & "comp.duration=" & 1 + (Int(HightestTrackTime * 1000) / 1000) & vbCrLf



        'Add a BACKGROUND (white?)
        '  " & vbCrLf
        m = m & "mySolid = comp.layers.addSolid([1,1,1],""White Background""," & ScreenX & "," & ScreenY & ",1," & 1 + (Int(HightestTrackTime * 1000) / 1000) & ");" & vbCrLf
        m = m & "mySolid.threeDLayer=true;" & vbCrLf
        m = m & "myPosition = mySolid.property(""position"");" & vbCrLf
        m = m & "myPosition.setValueAtTime(0,[" & ScreenX / 2 & "," & ScreenY / 2 & "," & 1000 & "]);" & vbCrLf
        m = m & "opac = mySolid.property(""Scale"");" & vbCrLf
        m = m & "opac.setValueAtTime(0,[10000,10000,100]);" & vbCrLf

        'ADD all the solids

        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        My.Computer.FileSystem.WriteAllText(MyOutputfile, m, True)


        Dim Vel2AE
        Dim newF As Double
        Dim newT As Double
        ttemp = ""
        Dim t2 As Double

        Dim posY As Integer
        Dim posW As Integer
        Dim posX As Integer
        Dim posZ As Integer
        Dim posWidth As Integer

        Dim KeyIndexIndex As Integer

        ProgressBar1.Maximum = MIDIevents.Count
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = Trim(Str(MIDIevents(Index).me_note))
                yn = chanUsed(MIDIevents(Index).me_Midi_Channel, 4)

                'Find the Velocity (or a noteoff event)
                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0

                'dont need values for noteoffs, because myvalue will be the Note's actual msecs_length
                If Vel2AE <> 0 Then

                    'Adjust the event TIME to only occur at FRAMES.
                    newF = (MIDIevents(Index).me_Secs_into_Track) / (1 / CInt(TextBox2.Text))
                    If (newF - Int(newF)) > 0.5 Then
                        newF = Int(newF) + 1
                    Else
                        newF = Int(newF)
                    End If
                    'If there is already an offset for that Midi channel, then adjust the Frame
                    newF = newF - YNoffset(yn) : YNoffset(yn) = 0
                    'If there is already an entry for that Frame on that Channel, then offset the Frame.
                    If newF = LastYN(yn) Then newF = newF + 1 : YNoffset(yn) = YNoffset(yn) + 1
                    LastYN(yn) = newF

                    'convert Frame to Time (based on chosen FPS)
                    newT = newF * (1 / CInt(TextBox2.Text))

                    'posY = UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) * heightscale
                    posY = (MIDIevents(Index).me_note - LowestNote + 1) * heightscale

                    posW = MIDIevents(Index).me_mSecs_length * widthscale
                    posX = Int(newT * widthscale)
                    posZ = MIDIevents(Index).me_Midi_Channel * 50
                    posWidth = 1 + (MIDIevents(Index).me_mSecs_length * widthscale)

                    'Store each Note's position in the 3d grid.
                    MIDIevents(Index).me_posX = 100 + posX
                    MIDIevents(Index).me_posY = ScreenY - posY
                    MIDIevents(Index).me_posZ = posZ
                    MIDIevents(Index).me_posTime = (Int(newT * 1000) / 1000)
                    ttemp = ""
                    'Create a Solid and set it's position
                    ttemp = ttemp & "mySolid = comp.layers.addSolid([" & mc(MIDIevents(Index).me_Midi_Channel, 1) & "," & mc(MIDIevents(Index).me_Midi_Channel, 2) & "," & mc(MIDIevents(Index).me_Midi_Channel, 3) & "], """ & MIDIevents(Index).me_Midi_Channel & " " & MIDIevents(Index).me_note & """," & posWidth & "," & heightscale & ", 1," & 1000 & ");" & vbCrLf
                    ttemp = ttemp & "mySolid.threeDLayer=true;" & vbCrLf
                    ttemp = ttemp & "myPosition = mySolid.property(""position"");" & vbCrLf
                    ttemp = ttemp & "myPosition.setValueAtTime(0,[" & MIDIevents(Index).me_posX & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf
                    KeyIndexIndex = 1

                    ''ttemp = ttemp & "var brco = mySolid(""Effects"").addProperty(""Brightness & Contrast"");" & vbCrLf
                    ''ttemp = ttemp & "var brcoBR = brco.Brightness;" & vbCrLf
                    ''ttemp = ttemp & "var brcoCO = brco.Contrast;" & vbCrLf
                    ttemp = ttemp & "opac = mySolid.property(""Scale"");" & vbCrLf
                    'SET keyframes at start of each track

                    ''ttemp = ttemp & "brcoBR.setValueAtTime(0,0);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setValueAtTime(0,0);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    'nearestKeyIndex(time)

                    ttemp = ttemp & "opac.setValueAtTime(0,[100,100]);" & vbCrLf
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.HOLD);" & vbCrLf


                    'SET keyframes for the event start
                    ''ttemp = ttemp & "brcoBR.setValueAtTime(" & newT & ",100);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setValueAtTime(" & newT & ",100);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    If newT <> 0 Then KeyIndexIndex = KeyIndexIndex + 1

                    ttemp = ttemp & "opac.setValueAtTime(" & MIDIevents(Index).me_posTime & ",[100,300]);" & vbCrLf
                    'allow bezier reduction
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.LINEAR);" & vbCrLf


                    'SET keyframes at the end of the event
                    ''ttemp = ttemp & "brcoBR.setValueAtTime(" & newT + MIDIevents(Index).me_mSecs_length & ", 0);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf

                    ''ttemp = ttemp & "brcoCO.setValueAtTime(" & newT + MIDIevents(Index).me_mSecs_length & ", 0);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    KeyIndexIndex = KeyIndexIndex + 1
                    t2 = (Int((newT + (MIDIevents(Index).me_mSecs_length * 0.95)) * 1000) / 1000)
                    If t2 = MIDIevents(Index).me_posTime Then
                        t2 = t2 + 0.001 'to prevent the third value being the same as the 2nd.
                    End If
                    ttemp = ttemp & "opac.setValueAtTime(" & t2 & ",[100,100]);" & vbCrLf
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.LINEAR);" & vbCrLf


                    My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, True)

                End If

            End If
            ProgressBar1.Value = Index
        Next
        ' ttemp = m & ttemp & "}"


        'ADD LIGHTS
        ''Note:  Array Lights(,) '0=name,1=Intensity,2=startX,3=startY, 4=startZ,5=endX,6=endY,7=endZ,8=coneangle,9 POIstartX,10 POIstartY,11 POIstartZ,12 POIendX,13 POIendY,14 POIendZ
        Dim Lights(,) = { _
        {"bottom 3rd", 180, 7500, ScreenY * (5 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"mid 3rd", 660, 7500, ScreenY * (2 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"top 3rd", 180, 7500, ScreenY * (-1 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"make ambient", 13, 7500, 11000, -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}}

        ''NOTE - NEED TO ADD CODE FOR THE ABOVE



        'ADD standard Cameras

        ''Note:  Array Cameras(,) '0=name,1=zoom,2=startX,3=startY, 4=startZ,5=endX,6=endY,7=endZ,8=orientX,9=orientY,10=orientZ
        Dim cameras(,) = { _
        {"Whole image", 270000, ScreenX / 2, ScreenY / 2, -300000, ScreenX / 2, ScreenY / 2, -300000, 0, 0, 0}, _
        {"top third", 2200, 0, ScreenY * (1 / 6), -1100, ScreenX, ScreenY * (1 / 6), -1100, 0, 0, 0}, _
        {"mid third", 2200, 0, ScreenY * (3 / 6), -1100, ScreenX, ScreenY * (3 / 6), -1100, 0, 0, 0}, _
        {"low third", 2200, 0, ScreenY * (5 / 6), -1100, ScreenX, ScreenY * (5 / 6), -1100, 0, 0, 0}, _
        {"mid.low angle", 1100, 0, ScreenY * (3 / 6), -450, ScreenX, ScreenY * (3 / 6), -450, 0, 20, 90}, _
{"top.low angle", 1100, 0, ScreenY * (1 / 6), -450, ScreenX, ScreenY * (1 / 6), -450, 0, 20, 90}, _
{"low.low angle", 1100, 0, ScreenY * (5 / 6), -450, ScreenX, ScreenY * (5 / 6), -450, 0, 20, 90} _
}

        m = ""
        For f = 0 To UBound(cameras)
            m = m & "cam2 = comp.layers.addCamera(""" & cameras(f, 0) & """,[25,250]);" & vbCrLf
            m = m & "cam2.inPoint = 00;" & vbCrLf
            m = m & "cam2.outPoint =" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
            m = m & "p1= cam2.transform(""position"")" & vbCrLf
            m = m & "p1.setValueAtTime(0,[" & cameras(f, 2) & "," & cameras(f, 3) & "," & cameras(f, 4) & "]);" & vbCrLf
            m = m & "p1.setValueAtTime(" & HightestTrackTime & ",[" & cameras(f, 5) & "," & cameras(f, 6) & "," & cameras(f, 7) & "]);" & vbCrLf
            '        m = m & "cam2.property(""position"").setValue([" & 0 & "," & ScreenY * (1 / 6) & ",-1100]);" & vbCrLf
            'need point of interest
            'm = m & "cam1.property(""anchorPoint"").setValue([0, 0, 0]);" & vbCrLf
            m = m & "cam2.property(""zoom"").setValue(" & cameras(f, 1) & ");" & vbCrLf
            m = m & "cam2.autoOrient = AutoOrientType.NO_AUTO_ORIENT;" & vbCrLf
            m = m & "my3=cam2.transform(""orientation"");" & vbCrLf
            m = m & "my3.setValueAtTime(0,[" & cameras(f, 8) & "," & cameras(f, 9) & "," & cameras(f, 10) & "]);" & vbCrLf
            'm = m & "my3.setValueAtTime(12,[0,0,0]);" & vbCrLf

            'Add Markers to the first Camera only
            If f = 0 Then
                m = m & "var myMarker = new MarkerValue(""demo marker"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(2, myMarker);" & vbCrLf
                m = m & "var myMarker = new MarkerValue(""Fade down"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(11.4, myMarker);" & vbCrLf
                m = m & "var myMarker = new MarkerValue(""Fade it"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(15, myMarker);" & vbCrLf
            End If
        Next

        'Add CAMERA which has the POI as the current note (works best for monophonic files)

        m = m & "cam2 = comp.layers.addCamera(""" & "Roving POI" & """,[25,250]);" & vbCrLf
        m = m & "cam2.inPoint = 00;" & vbCrLf
        m = m & "cam2.outPoint =" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
        m = m & "p1= cam2.transform(""position"")" & vbCrLf
        m = m & "p1.setValueAtTime(0,[" & ScreenX * (0 / 6) & "," & ScreenY * (3 / 6) & "," & -10000 & "]);" & vbCrLf
        m = m & "p1.setValueAtTime(" & HightestTrackTime & ",[" & ScreenX * (0 / 6) & "," & ScreenX * (6 / 6) & "," & -10000 & "]);" & vbCrLf
        '       m = m & "cam1.property(""anchorPoint"").setValue([0, 0, 0]);" & vbCrLf
        m = m & "cam2.property(""zoom"").setValue(" & 1100 & ");" & vbCrLf
        m = m & "cam2.autoOrient = AutoOrientType.CAMERA_OR_POINT_OF_INTEREST;" & vbCrLf

        'add all the POI changes.
        m = m & "my3=cam2.pointOfInterest;" & vbCrLf
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                m = m & "my3.setValueAtTime(" & MIDIevents(Index).me_posTime & ",[" & MIDIevents(Index).me_posX & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf
            End If
        Next







        My.Computer.FileSystem.WriteAllText(MyOutputfile, m & vbCrLf & "}", True)

        ''My.Computer.FileSystem.WriteAllText("C:\Test.txt", String.Empty, False)



h:
        'IntResult = 0
        'Try
        ' My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, False)
        'Catch ex As Exception
        'IntResult = MsgBox(ex.Message, MsgBoxStyle.RetryCancel)
        'End Try
        'If IntResult = DialogResult.Retry Then
        ''Else : MsgBox(IntResult)
        'GoTo h
        'End If
        ProgressBar1.Value = 0
        SaveAEscript3 = True

    End Function
    Function SaveVRMLscript1()
        'As used by jingle bells


        MyOutputfile = GetjsxOutputfile(".wrl")
        

        'populate the values of me_mSecs_length
        Calculate_me_mSecs_length()


        Dim ttemp = ""
        Dim IntResult = 0
        Dim fflag = 0
        Dim m As String = ""
        Dim anim As String = ""
        Dim rout As String = ""
        Dim xn As String = "0000"
        Dim yn As String = "0000"
        Dim Index As Integer
        Dim f As Integer
        Dim d As Integer
        'Finding out about the distribution of Notes and Channels

        Dim chanUsed(16, 4)
        ' 1= flag(is the channel used), 2=lowest Note on channel, 3=highest note on channel, 4= POINTER reference
        Dim pointerReference As Integer = 1
        For Index = 0 To 16
            chanUsed(Index, 1) = 0
            chanUsed(Index, 2) = 128
            chanUsed(Index, 3) = 0
            chanUsed(Index, 4) = 0
        Next
        'For each Event: find the highest and lowest notes for each channel;and remember which channels have actually been used.
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 2)) > CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 3)) < CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 3) = MIDIevents(Index).me_note
                End If
                chanUsed(MIDIevents(Index).me_Midi_Channel, 1) = 1
                If chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = 0 Then chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = pointerReference : pointerReference = pointerReference + 1
            End If
        Next

        'Find Highest and Lowest within all channels
        Dim HighestNote = 0
        Dim LowestNote = 127
        For Index = 0 To 16
            If chanUsed(Index, 3) > HighestNote Then HighestNote = chanUsed(Index, 3)
            If chanUsed(Index, 2) < LowestNote Then LowestNote = chanUsed(Index, 2)
        Next

        Dim UsageMap(16, 128, 2) ' 16 channels of 128 notes. 1=flag if used, 2=note order
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = 1
            End If
        Next

        For f = 0 To 16
            Index = 1
            For d = 0 To 128
                If UsageMap(f, d, 1) = 1 Then UsageMap(f, d, 2) = Index : Index = Index + 1
            Next
        Next

        'get the midi filename
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)

        'set the colours for each midi channel
        Dim mc(16, 3) As Double
        mc(0, 1) = 0.8 : mc(0, 2) = 0.5 : mc(0, 3) = 0.3
        mc(1, 1) = 1 : mc(1, 2) = 0.0 : mc(1, 3) = 0.0
        mc(2, 1) = 0 : mc(2, 2) = 1.0 : mc(2, 3) = 0.0 'green
        mc(3, 1) = 0 : mc(3, 2) = 0.0 : mc(3, 3) = 1.0
        mc(4, 1) = 0.1 : mc(4, 2) = 0.6 : mc(4, 3) = 0.8
        mc(5, 1) = 0.4 : mc(5, 2) = 1.0 : mc(5, 3) = 0.6
        mc(6, 1) = 0 : mc(6, 2) = 1.0 : mc(6, 3) = 1.0
        mc(7, 1) = 1 : mc(7, 2) = 0.0 : mc(7, 3) = 1.0
        mc(8, 1) = 0.5 : mc(8, 2) = 1.0 : mc(8, 3) = 0.0
        mc(9, 1) = 0.5 : mc(9, 2) = 0.5 : mc(9, 3) = 1.0
        mc(10, 1) = 0.5 : mc(10, 2) = 0.3 : mc(10, 3) = 0.2
        mc(11, 1) = 0.7 : mc(11, 2) = 0.2 : mc(11, 3) = 0.7
        mc(12, 1) = 0.7 : mc(12, 2) = 0.1 : mc(12, 3) = 1.0
        mc(13, 1) = 0.2 : mc(13, 2) = 0.8 : mc(13, 3) = 0.5
        mc(14, 1) = 0.2 : mc(14, 2) = 0.1 : mc(14, 3) = 0.5
        mc(15, 1) = 0.2 : mc(15, 2) = 0.2 : mc(15, 3) = 1.0
        mc(16, 1) = 0.5 : mc(16, 2) = 0.0 : mc(16, 3) = 0.0

        ''''''''''''''''''''''''''''''''''''
        'The shape of the blocks collection
        Dim ScreenY = CInt(TextBox4.Text)
        Dim ScreenX = CInt(TextBox3.Text)
        Dim heightscale = (ScreenY / (HighestNote - LowestNote)) ' range of notes  
        Dim widthscale = (ScreenX / (HightestTrackTime))

        'The size of each block
        Dim BlockHeight = CInt(TextBox6.Text)
        Dim BlockWidth = CInt(TextBox5.Text)


        ' m boxes
        ' anim timings
        ' rout routes

        m = "#VRML V2.0 utf8" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "DEF tima1 Transform {" & vbCrLf
        m = m & "  scale .5 .5 .5" & vbCrLf
        m = m & "children [" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
       
        anim = anim & "NavigationInfo { type ""EXAMINE"" }"
        anim = anim & "" & vbCrLf
        anim = anim & "# Animation clock" & vbCrLf
        anim = anim & "DEF Clock TimeSensor { cycleInterval " & HightestTrackTime & " loop TRUE  }" & vbCrLf
        anim = anim & "# Animation path" & vbCrLf
        anim = anim & "" & vbCrLf

        'ADD all the solids

        'm = m & "" & vbCrLf
        'm = m & "" & vbCrLf
        'My.Computer.FileSystem.WriteAllText(MyOutputfile, m, True)


        Dim Vel2AE
        ttemp = ""


        Dim posY As Integer
        Dim posW As Integer
        Dim posX As Integer
        Dim posZ As Integer
        Dim posWidth As Integer

        
        ProgressBar1.Maximum = MIDIevents.Count
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = Trim(Str(MIDIevents(Index).me_note))
                yn = chanUsed(MIDIevents(Index).me_Midi_Channel, 4)

                'Find the Velocity (or a noteoff event)
                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0

                'dont need values for noteoffs, because myvalue will be the Note's actual msecs_length
                If Vel2AE <> 0 Then

                    'Adjust the event TIME to only occur at FRAMES.
                    'newF = MIDIevents(Index).me_Secs_into_Track



                    'posY = UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) * heightscale
                    posY = (MIDIevents(Index).me_note - LowestNote + 1) * heightscale
                    posW = MIDIevents(Index).me_mSecs_length * widthscale
                    posX = (MIDIevents(Index).me_Secs_into_Track * widthscale)
                    posZ = MIDIevents(Index).me_Midi_Channel * 40

                    If RadioButton3.Enabled Then posWidth = (NumericUpDown1.Value / 100) * (MIDIevents(Index).me_mSecs_length * widthscale)
                    If RadioButton2.Enabled Then posWidth = CDbl(TextBox8.Text)


                    'Store each Note's position in the 3d grid.
                    MIDIevents(Index).me_posX = posX
                    MIDIevents(Index).me_posY = posY
                    MIDIevents(Index).me_posZ = posZ
                    MIDIevents(Index).me_posTime = MIDIevents(Index).me_Secs_into_Track 'newT
                    ttemp = ""

                    'Create a Solid
                    m = m & "DEF vbox" & Trim(Str(Index)) & " Transform {" & vbCrLf
                    m = m & "translation " & MIDIevents(Index).me_posX & " " & MIDIevents(Index).me_posY & " " & MIDIevents(Index).me_posZ & vbCrLf
                    m = m & "children [ Shape { appearance Appearance {" & vbCrLf
                    m = m & "material Material { diffuseColor " & mc(MIDIevents(Index).me_Midi_Channel, 1) & " " & mc(MIDIevents(Index).me_Midi_Channel, 2) & " " & mc(MIDIevents(Index).me_Midi_Channel, 3) & " } }" & vbCrLf
                    ''  m = m & "geometry Box { size " & posWidth & " 10 10 }        }      ]    }" & vbCrLf
                    m = m & "geometry Box { size " & posWidth & " " & BlockHeight & " " & BlockWidth & " }        }      ]    }" & vbCrLf
                    m = m & "" & vbCrLf
                    m = m & "" & vbCrLf

                    'Create the animation timing
                    'Set Events at 0, just before the note, at the note start, at the note end, and just after the note ends.
                    anim = anim & "DEF vpath" & Trim(Str(Index)) & " PositionInterpolator {" & vbCrLf
                    anim = anim & "key [ 0," & (MIDIevents(Index).me_Secs_into_Track - 1) / HightestTrackTime & "," & MIDIevents(Index).me_Secs_into_Track / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length) / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length + 1) / HightestTrackTime & "]" & vbCrLf
                    anim = anim & "keyValue [1.0 1.0 1.0, 1.0 1.0 1.0,  2.0 2.0 3.0, 1.0 1.0 1.0, 1.0 1.0 1.0 ]" & vbCrLf
                    anim = anim & "}" & vbCrLf
                    anim = anim & "" & vbCrLf
                    anim = anim & "" & vbCrLf
                    anim = anim & "" & vbCrLf
                    anim = anim & "" & vbCrLf

                    'Create the routes
                    rout = rout & "ROUTE Clock.fraction_changed  TO vpath" & Trim(Str(Index)) & ".set_fraction" & vbCrLf
                    rout = rout & "ROUTE vpath" & Trim(Str(Index)) & ".value_changed TO vbox" & Trim(Str(Index)) & ".set_scale" & vbCrLf
                    rout = rout & "" & vbCrLf

                    'ALTERNATIVE - Each Box rotates, instead of expanding
                    'anim = anim & "DEF vpath" & Trim(Str(Index)) & " OrientationInterpolator {" & vbCrLf
                    'anim = anim & "key [ 0," & (MIDIevents(Index).me_Secs_into_Track - 1) / HightestTrackTime & "," & MIDIevents(Index).me_Secs_into_Track / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length) / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length + 1) / HightestTrackTime & "]" & vbCrLf
                    'anim = anim & "keyValue [1 0 0 0, 1 0 0 0,  1 0 0  180, 1 0 0 0, 1 0 0 0]" & vbCrLf
                    'anim = anim & "}" & vbCrLf
                    'Create the routes
                    'rout = rout & "ROUTE Clock.fraction_changed  TO vpath" & Trim(Str(Index)) & ".set_fraction" & vbCrLf
                    'rout = rout & "ROUTE vpath" & Trim(Str(Index)) & ".value_changed TO vbox" & Trim(Str(Index)) & ".set_rotation" & vbCrLf
                    'rout = rout & "" & vbCrLf

                End If

            End If
            ProgressBar1.Value = Index
        Next
        ' ttemp = m & ttemp & "}"


        '3ds max 2010 wants an ansi file - not uft or unicode.
        Dim marray() As Byte

        'MyOutputfile, m & vbCrLf & anim & vbCrLf & " ] } " & vbCrLf & rout & vbCrLf & "", True)
        Dim fStream As New FileStream(MyOutputfile, FileMode.Create)
        Dim bw As New BinaryWriter(fStream)
        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(m)

        Dim i As Integer
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next

        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(anim)
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next

        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(" ] } ")
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next


        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(rout)
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next


        bw.Close()
        fStream.Close()


h:
        
        ProgressBar1.Value = 0
        SaveVRMLscript1 = True

    End Function

    Function SaveVRMLscript2()
        'single notes played many times.
        'all occurences of a particular note and channel are 'played' by the same InstrumentNote.
        '2 sets are produced. One spaces the Notes in a real distance apart. The second bunches the played notes together.

        MyOutputfile = GetjsxOutputfile(".wrl")


        'populate the values of me_mSecs_length
        Calculate_me_mSecs_length()


        Dim ttemp = ""
        Dim IntResult = 0
        Dim fflag = 0
        Dim m As String = ""
        Dim anim As String = ""
        Dim rout As String = ""
        Dim xn As String = "0000"
        Dim yn As String = "0000"
        Dim Index As Integer
        Dim f As Integer
        Dim d As Integer

        'Finding out about the distribution of Notes and Channels

        Dim chanUsed(16, 4)
        ' 1= flag(is the channel used), 2=lowest Note on channel, 3=highest note on channel, 4= POINTER reference
        Dim pointerReference As Integer = 1
        For Index = 0 To 16
            chanUsed(Index, 1) = 0
            chanUsed(Index, 2) = 128
            chanUsed(Index, 3) = 0
            chanUsed(Index, 4) = 0
        Next
        'For each Event: find the highest and lowest notes for each channel;and remember which channels have actually been used.
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 2)) > CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 3)) < CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 3) = MIDIevents(Index).me_note
                End If
                chanUsed(MIDIevents(Index).me_Midi_Channel, 1) = 1
                If chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = 0 Then chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = pointerReference : pointerReference = pointerReference + 1
            End If
        Next

        'Find Highest and Lowest within all channels
        Dim HighestNote = 0
        Dim LowestNote = 127
        For Index = 0 To 16
            If chanUsed(Index, 3) > HighestNote Then HighestNote = chanUsed(Index, 3)
            If chanUsed(Index, 2) < LowestNote Then LowestNote = chanUsed(Index, 2)
        Next

        Dim UsageMap(16, 128, 2) ' 16 channels, 128 notes, 1=flag if used, 2=number of occurences
        Dim UsageMapVRML(16, 128, 3) 'text1 = vrml vpath for each Box's movements,2=keyvalues, 3rd is the Objects VRML name
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = 1
            End If
        Next

        For f = 0 To 16
            Index = 1
            For d = 0 To 128
                If UsageMap(f, d, 1) = 1 Then UsageMap(f, d, 2) = Index : Index = Index + 1
            Next
        Next

        'get the midi filename
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)

        'set the colours for each midi channel
        Dim mc(16, 3) As Double
        mc(0, 1) = 0.8 : mc(0, 2) = 0.5 : mc(0, 3) = 0.3
        mc(1, 1) = 1 : mc(1, 2) = 0.0 : mc(1, 3) = 0.0
        mc(2, 1) = 0 : mc(2, 2) = 1.0 : mc(2, 3) = 0.0 'green
        mc(3, 1) = 0 : mc(3, 2) = 0.0 : mc(3, 3) = 1.0
        mc(4, 1) = 0.1 : mc(4, 2) = 0.6 : mc(4, 3) = 0.8
        mc(5, 1) = 0.4 : mc(5, 2) = 1.0 : mc(5, 3) = 0.6
        mc(6, 1) = 0 : mc(6, 2) = 1.0 : mc(6, 3) = 1.0
        mc(7, 1) = 1 : mc(7, 2) = 0.0 : mc(7, 3) = 1.0
        mc(8, 1) = 0.5 : mc(8, 2) = 1.0 : mc(8, 3) = 0.0
        mc(9, 1) = 0.5 : mc(9, 2) = 0.5 : mc(9, 3) = 1.0
        mc(10, 1) = 0.5 : mc(10, 2) = 0.3 : mc(10, 3) = 0.2
        mc(11, 1) = 0.7 : mc(11, 2) = 0.2 : mc(11, 3) = 0.7
        mc(12, 1) = 0.7 : mc(12, 2) = 0.1 : mc(12, 3) = 1.0
        mc(13, 1) = 0.2 : mc(13, 2) = 0.8 : mc(13, 3) = 0.5
        mc(14, 1) = 0.2 : mc(14, 2) = 0.1 : mc(14, 3) = 0.5
        mc(15, 1) = 0.2 : mc(15, 2) = 0.2 : mc(15, 3) = 1.0
        mc(16, 1) = 0.5 : mc(16, 2) = 0.0 : mc(16, 3) = 0.0

        ''''''''''''''''''''''''''''''''''''
        'scale down gracefully 20480 by 11520, div by 16 gives 1280 by 720
        Dim ScreenX = 600
        Dim ScreenY = 300
        Dim heightscale = (ScreenY / (HighestNote - LowestNote)) ' range of notes  
        Dim widthscale = (ScreenX / (HightestTrackTime))




        ' m boxes
        ' anim timings
        ' rout routes

        m = "#VRML V2.0 utf8" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "DEF tima2 Transform {" & vbCrLf
        m = m & "  scale 1 1 1" & vbCrLf
        m = m & "children [" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf

        anim = anim & "NavigationInfo { type ""EXAMINE"" }"
        anim = anim & "" & vbCrLf
        anim = anim & "# Animation clock" & vbCrLf
        anim = anim & "DEF Clock TimeSensor { cycleInterval " & HightestTrackTime & " loop TRUE  }" & vbCrLf
        anim = anim & "# Animation path" & vbCrLf
        anim = anim & "" & vbCrLf

        'ADD all the solids

        'm = m & "" & vbCrLf
        'm = m & "" & vbCrLf
        'My.Computer.FileSystem.WriteAllText(MyOutputfile, m, True)


        Dim Vel2AE
        ttemp = ""


        Dim posY As Integer
        Dim posW As Integer
        Dim posX As Integer
        Dim posZ As Integer
        Dim posWidth As Integer


        ProgressBar1.Maximum = MIDIevents.Count
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = Trim(Str(MIDIevents(Index).me_note))
                yn = chanUsed(MIDIevents(Index).me_Midi_Channel, 4)

                'Find the Velocity (or a noteoff event)
                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0

                'dont need values for noteoffs, because myvalue will be the Note's actual msecs_length
                If Vel2AE <> 0 Then

                    'Adjust the event TIME to only occur at FRAMES.
                    'newF = MIDIevents(Index).me_Secs_into_Track



                    'posY = UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) * heightscale
                    posY = (MIDIevents(Index).me_note - LowestNote + 1) * heightscale
                    posW = MIDIevents(Index).me_mSecs_length * widthscale
                    posX = (MIDIevents(Index).me_Secs_into_Track * widthscale)
                    posZ = MIDIevents(Index).me_Midi_Channel * 40
                    posWidth = 1 + (MIDIevents(Index).me_mSecs_length * widthscale)

                    'Store each Note's position in the 3d grid.
                    MIDIevents(Index).me_posX = posX
                    MIDIevents(Index).me_posY = posY
                    MIDIevents(Index).me_posZ = posZ
                    MIDIevents(Index).me_posTime = MIDIevents(Index).me_Secs_into_Track 'newT
                    ttemp = ""

                    ''Create a Solid
                    'm = m & "DEF vbox" & Trim(Str(Index)) & " Transform {" & vbCrLf
                    'm = m & "translation " & MIDIevents(Index).me_posX & " " & MIDIevents(Index).me_posY & " " & MIDIevents(Index).me_posZ & vbCrLf
                    'm = m & "children [ Shape { appearance Appearance {" & vbCrLf
                    'm = m & "material Material { diffuseColor " & mc(MIDIevents(Index).me_Midi_Channel, 1) & " " & mc(MIDIevents(Index).me_Midi_Channel, 2) & " " & mc(MIDIevents(Index).me_Midi_Channel, 3) & " } }" & vbCrLf
                    'm = m & "geometry Box { size " & posWidth & " 10 10 }        }      ]    }" & vbCrLf
                    'm = m & "" & vbCrLf
                    'm = m & "" & vbCrLf

                    ''Create the animation timing
                    'anim = anim & "DEF vpath" & Trim(Str(Index)) & " PositionInterpolator {" & vbCrLf
                    'anim = anim & "key [ 0," & (MIDIevents(Index).me_Secs_into_Track - 1) / HightestTrackTime & "," & MIDIevents(Index).me_Secs_into_Track / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length) / HightestTrackTime & "," & (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length + 1) / HightestTrackTime & "]" & vbCrLf
                    'anim = anim & "keyValue [1.0 1.0 1.0, 1.0 1.0 1.0,  2.0 2.0 3.0, 1.0 1.0 1.0, 1.0 1.0 1.0 ]" & vbCrLf
                    'anim = anim & "}" & vbCrLf

                    'Create the animation timing

                    'Add a comma if not the first entry
                    If UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) <> "" Then
                        UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) & ","
                    End If
                   
                    'add 'just before event' value, event, end of the event.                
                    UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = _
                    UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) & _
                                    (MIDIevents(Index).me_Secs_into_Track - 0.09) / HightestTrackTime & "," & _
                                      MIDIevents(Index).me_Secs_into_Track / HightestTrackTime & "," & _
                                    (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length) / HightestTrackTime '& "," & _

                    
                    If UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) <> "" Then
                        UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) = _
                        UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) & ","
                    End If
                    UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) = _
                    UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) & _
                    "0 0 0 1,0 0 1 .9, 0 0 1 0"

                    ' UsageMapVRML(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 3) = "vpath" & Trim(Str(Index))

                    ' (MIDIevents(Index).me_Secs_into_Track - 0.01) / HightestTrackTime & "," & _
                    '                    (MIDIevents(Index).me_Secs_into_Track + MIDIevents(Index).me_mSecs_length + 0.01) / HightestTrackTime


                End If

            End If
            ProgressBar1.Value = Index
        Next
        ' ttemp = m & ttemp & "}"


        '3ds max 2010 wants an ansi file - not uft or unicode.
        Dim marray() As Byte

        'MyOutputfile, m & vbCrLf & anim & vbCrLf & " ] } " & vbCrLf & rout & vbCrLf & "", True)
        Dim fStream As New FileStream(MyOutputfile, FileMode.Create)
        Dim bw As New BinaryWriter(fStream)

        
        
        Dim vname = ""
        'anim = ""
        For f = 0 To 16
            For d = 0 To 128
                If UsageMap(f, d, 1) = 1 Then
                    vname = Trim(Str(f)) & "_" & Trim(Str(d))

                    'Create a Solid
                    m = m & "DEF vbox" & vname & " Transform {" & vbCrLf
                    'm = m & "translation " & MIDIevents(Index).me_posX & " " & MIDIevents(Index).me_posY & " " & MIDIevents(Index).me_posZ & vbCrLf
                    m = m & "translation " & d * 11 & " " & 15 & " " & f * 12 & vbCrLf
                    m = m & "children [ Shape { appearance Appearance {" & vbCrLf
                    m = m & "material Material { diffuseColor " & mc(f, 1) & " " & mc(f, 2) & " " & mc(f, 3) & " } }" & vbCrLf
                    m = m & "geometry Box { size " & 3 & " 20 10 }        }      ]    }" & vbCrLf
                    m = m & "" & vbCrLf


                    anim = anim & "DEF vpath" & vname & " OrientationInterpolator {" & vbCrLf
                    anim = anim & "key [ " & UsageMapVRML(f, d, 1) & "]" & vbCrLf
                    anim = anim & "keyValue [" & UsageMapVRML(f, d, 2) & "]" & vbCrLf
                    anim = anim & "}" & vbCrLf


                    'Create the routes
                    rout = rout & "ROUTE Clock.fraction_changed  TO vpath" & vname & ".set_fraction" & vbCrLf
                    rout = rout & "ROUTE vpath" & vname & ".value_changed TO vbox" & vname & ".set_rotation" & vbCrLf
                    rout = rout & "" & vbCrLf
                End If
                'Console.WriteLine(d)
            Next

        Next

        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(m)
        Dim i As Integer
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next



        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(anim)
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next

        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(" ] } ")
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next


        marray = System.Text.Encoding.GetEncoding(1252).GetBytes(rout)
        For i = 0 To UBound(marray)
            bw.Write(marray(i))
        Next


        bw.Close()
        fStream.Close()


h:

        ProgressBar1.Value = 0
        SaveVRMLscript2 = True

    End Function


    Function SaveAEscript5()
        'As used in Kick
        'save Frame,Midichannel, Note, Velocity, Length

        MyOutputfile = GetjsxOutputfile(".jsx")
        My.Computer.FileSystem.WriteAllText(MyOutputfile, "", False)


        'populate the values of me_mSecs_length
        Calculate_me_mSecs_length()


        Dim ttemp = ""
        Dim IntResult = 0
        Dim fflag = 0
        Dim m As String = ""
        Dim xn As String = "0000"
        Dim yn As String = "0000"
        Dim Index As Integer
        Dim f As Integer
        Dim d As Integer

        'Finding out about the distribution of Notes and Channels

        Dim chanUsed(16, 4)
        ' 1= flag(is the channel used), 2=lowest Note on channel, 3=highest note on channel, 4= POINTER reference
        Dim pointerReference As Integer = 1
        For Index = 0 To 16
            chanUsed(Index, 1) = 0
            chanUsed(Index, 2) = 128
            chanUsed(Index, 3) = 0
            chanUsed(Index, 4) = 0
        Next
        'For each Event: find the highest and lowest notes for each channel;and remember which channels have actually been used.
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 2)) > CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 3)) < CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 3) = MIDIevents(Index).me_note
                End If
                chanUsed(MIDIevents(Index).me_Midi_Channel, 1) = 1
                If chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = 0 Then chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = pointerReference : pointerReference = pointerReference + 1
            End If
        Next

        'Find Highest and Lowest within all channels
        Dim HighestNote = 0
        Dim LowestNote = 127
        For Index = 0 To 16
            If chanUsed(Index, 3) > HighestNote Then HighestNote = chanUsed(Index, 3)
            If chanUsed(Index, 2) < LowestNote Then LowestNote = chanUsed(Index, 2)
        Next

        Dim UsageMap(16, 128, 2) ' 16 channels of 128 notes. 1=flag if used, 2=note order
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 1) = 1
            End If
        Next

        For f = 0 To 16
            Index = 1
            For d = 0 To 128
                If UsageMap(f, d, 1) = 1 Then UsageMap(f, d, 2) = Index : Index = Index + 1
            Next
        Next

        'get the midi filename
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyMidi = MyFile.Substring(a, Len(MyFile) - a - 4)

        'set the colours for each midi channel
        Dim mc(16, 3) As Integer
        mc(0, 1) = 1 : mc(16, 2) = 0.5 : mc(16, 3) = 0.3
        mc(1, 1) = 1 : mc(1, 2) = 0.0 : mc(1, 3) = 0.0
        mc(2, 1) = 0 : mc(2, 2) = 1.0 : mc(2, 3) = 0.0 'green
        mc(3, 1) = 0 : mc(3, 2) = 0.0 : mc(3, 3) = 1.0
        mc(4, 1) = 0.1 : mc(4, 2) = 0.6 : mc(4, 3) = 0.8
        mc(5, 1) = 0.4 : mc(5, 2) = 1.0 : mc(5, 3) = 0.6
        mc(6, 1) = 0 : mc(6, 2) = 1.0 : mc(6, 3) = 1.0
        mc(7, 1) = 1 : mc(7, 2) = 0.0 : mc(7, 3) = 1.0
        mc(8, 1) = 0.5 : mc(8, 2) = 1.0 : mc(8, 3) = 0.0
        mc(9, 1) = 0.5 : mc(9, 2) = 0.5 : mc(9, 3) = 1.0
        mc(10, 1) = 0.5 : mc(10, 2) = 0.3 : mc(10, 3) = 0.2
        mc(11, 1) = 0.7 : mc(11, 2) = 0.2 : mc(11, 3) = 0.7
        mc(12, 1) = 0.7 : mc(12, 2) = 0.1 : mc(12, 3) = 1.0
        mc(13, 1) = 0.2 : mc(13, 2) = 0.8 : mc(13, 3) = 0.5
        mc(14, 1) = 0.2 : mc(14, 2) = 0.1 : mc(14, 3) = 0.5
        mc(15, 1) = 0.2 : mc(15, 2) = 0.2 : mc(15, 3) = 1.0
        mc(16, 1) = 0.5 : mc(16, 2) = 0.0 : mc(16, 3) = 0.0

        ''''''''''''''''''''''''''''''''''''
        'scale down gracefully 20480 by 11520, div by 16 gives 1280 by 720
        Dim ScreenX = 20480
        Dim ScreenY = 11520
        Dim heightscale = Int(ScreenY / (HighestNote - LowestNote)) ' range of notes  
        Dim widthscale = Int(ScreenX / (HightestTrackTime))

        'MsgBox(HighestNote)
        '   MsgBox(LowestNote)
        'MsgBox(heightscale)
        'MsgBox(LowestNote)


        m = m & "{" & vbCrLf
        'm = m & "comp = app.project.activeItem;" & vbCrLf
        m = m & " var proj = app.project;" & vbCrLf
        m = m & "var projItems = proj.items;" & vbCrLf



        m = m & "var currentTime = new Date();" & vbCrLf
        m = m & "var hours = currentTime.getHours();" & vbCrLf
        m = m & "var minutes = currentTime.getMinutes();" & vbCrLf
        m = m & "var currentTime = new Date();" & vbCrLf
        m = m & "var month = currentTime.getMonth() + 1;" & vbCrLf
        m = m & "var day = currentTime.getDate();" & vbCrLf
        m = m & "var year = currentTime.getFullYear();" & vbCrLf
        m = m & "ctime=""" + MyMidi + " "" + hours + "":"" + minutes + "" "" +month + ""/"" + day + ""/"" + year;" & vbCrLf

        m = m & "var comp = projItems.addComp(ctime," & ScreenX & "," & ScreenY & ", 1, 5, 30);" & vbCrLf
        '  m = m & "comp.duration=" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
        m = m & "comp.duration=" & 1 + (Int(HightestTrackTime * 1000) / 1000) & vbCrLf



        'Add a BACKGROUND (white?)
        '  " & vbCrLf
        m = m & "mySolid = comp.layers.addSolid([1,1,1],""White Background""," & ScreenX & "," & ScreenY & ",1," & 1 + (Int(HightestTrackTime * 1000) / 1000) & ");" & vbCrLf
        m = m & "mySolid.threeDLayer=true;" & vbCrLf
        m = m & "myPosition = mySolid.property(""position"");" & vbCrLf
        m = m & "myPosition.setValueAtTime(0,[" & ScreenX / 2 & "," & ScreenY / 2 & "," & 1000 & "]);" & vbCrLf
        m = m & "opac = mySolid.property(""Scale"");" & vbCrLf
        m = m & "opac.setValueAtTime(0,[10000,10000,100]);" & vbCrLf

        'ADD all the solids

        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        My.Computer.FileSystem.WriteAllText(MyOutputfile, m, True)


        Dim Vel2AE
        Dim newF As Double
        Dim newT As Double
        ttemp = ""
        Dim t2 As Double

        Dim posY As Integer
        Dim posW As Integer
        Dim posX As Integer
        Dim posZ As Integer
        Dim posWidth As Integer

        Dim KeyIndexIndex As Integer

        ProgressBar1.Maximum = MIDIevents.Count
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = Trim(Str(MIDIevents(Index).me_note))
                yn = chanUsed(MIDIevents(Index).me_Midi_Channel, 4)

                'Find the Velocity (or a noteoff event)
                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0

                'dont need values for noteoffs, because myvalue will be the Note's actual msecs_length
                If Vel2AE <> 0 Then

                    'Adjust the event TIME to only occur at FRAMES.
                    newF = (MIDIevents(Index).me_Secs_into_Track) / (1 / CInt(TextBox2.Text))
                    If (newF - Int(newF)) > 0.5 Then
                        newF = Int(newF) + 1
                    Else
                        newF = Int(newF)
                    End If
                    'If there is already an offset for that Midi channel, then adjust the Frame
                    newF = newF - YNoffset(yn) : YNoffset(yn) = 0
                    'If there is already an entry for that Frame on that Channel, then offset the Frame.
                    If newF = LastYN(yn) Then newF = newF + 1 : YNoffset(yn) = YNoffset(yn) + 1
                    LastYN(yn) = newF

                    'convert Frame to Time (based on chosen FPS)
                    newT = newF * (1 / CInt(TextBox2.Text))

                    'posY = UsageMap(MIDIevents(Index).me_Midi_Channel, MIDIevents(Index).me_note, 2) * heightscale
                    posY = (MIDIevents(Index).me_note - LowestNote + 1) * heightscale

                    posW = MIDIevents(Index).me_mSecs_length * widthscale
                    posX = Int(newT * widthscale)
                    posZ = MIDIevents(Index).me_Midi_Channel * 50
                    posWidth = 1 + (MIDIevents(Index).me_mSecs_length * widthscale)

                    'Store each Note's position in the 3d grid.
                    MIDIevents(Index).me_posX = 100 + posX
                    MIDIevents(Index).me_posY = ScreenY - posY
                    MIDIevents(Index).me_posZ = posZ
                    MIDIevents(Index).me_posTime = (Int(newT * 1000) / 1000)
                    ttemp = ""
                    'Create a Solid and set it's position
                    ttemp = ttemp & "mySolid = comp.layers.addSolid([" & mc(MIDIevents(Index).me_Midi_Channel, 1) & "," & mc(MIDIevents(Index).me_Midi_Channel, 2) & "," & mc(MIDIevents(Index).me_Midi_Channel, 3) & "], """ & MIDIevents(Index).me_Midi_Channel & " " & MIDIevents(Index).me_note & """," & posWidth & "," & heightscale & ", 1," & 1000 & ");" & vbCrLf
                    ttemp = ttemp & "mySolid.threeDLayer=true;" & vbCrLf
                    ttemp = ttemp & "myPosition = mySolid.property(""position"");" & vbCrLf
                    ' 
                    'in the Midfile
                    ttemp = ttemp & "myPosition.setValueAtTime(0,[" & 50 & "," & 1000 & "," & 0 & "]);" & vbCrLf
                    'Separate Channels
                    ttemp = ttemp & "myPosition.setValueAtTime(" & 5 + MIDIevents(Index).me_posTime & ",[" & 1000 & "," & 1000 & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf
                    'separate notes
                    ttemp = ttemp & "myPosition.setValueAtTime(" & 10 + MIDIevents(Index).me_posTime & ",[" & 5000 & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf

                    'Separate Timing
                    ttemp = ttemp & "myPosition.setValueAtTime(" & 15 + MIDIevents(Index).me_posTime & ",[" & 10000 & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf

                    'read to Play)
                    ttemp = ttemp & "myPosition.setValueAtTime(" & 18 + MIDIevents(Index).me_posTime & ",[" & 12000 & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf
                    'after play
                    ttemp = ttemp & "myPosition.setValueAtTime(" & (21 + Int((newT + (MIDIevents(Index).me_mSecs_length * 0.95)) * 1000) / 1000) & ",[" & 20000 & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf



                    KeyIndexIndex = 1

                    ''ttemp = ttemp & "var brco = mySolid(""Effects"").addProperty(""Brightness & Contrast"");" & vbCrLf
                    ''ttemp = ttemp & "var brcoBR = brco.Brightness;" & vbCrLf
                    ''ttemp = ttemp & "var brcoCO = brco.Contrast;" & vbCrLf
                    ttemp = ttemp & "opac = mySolid.property(""Scale"");" & vbCrLf
                    'SET keyframes at start of each track

                    ''ttemp = ttemp & "brcoBR.setValueAtTime(0,0);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setValueAtTime(0,0);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    'nearestKeyIndex(time)

                    ttemp = ttemp & "opac.setValueAtTime(0,[100,100]);" & vbCrLf
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.HOLD);" & vbCrLf


                    'SET keyframes for the event start
                    ''ttemp = ttemp & "brcoBR.setValueAtTime(" & newT & ",100);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setValueAtTime(" & newT & ",100);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    If newT <> 0 Then KeyIndexIndex = KeyIndexIndex + 1

                    ttemp = ttemp & "opac.setValueAtTime(" & 20 + MIDIevents(Index).me_posTime & ",[100,350]);" & vbCrLf
                    'allow bezier reduction
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.LINEAR);" & vbCrLf


                    'SET keyframes at the end of the event
                    ''ttemp = ttemp & "brcoBR.setValueAtTime(" & newT + MIDIevents(Index).me_mSecs_length & ", 0);" & vbCrLf
                    ''ttemp = ttemp & "brcoBR.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf

                    ''ttemp = ttemp & "brcoCO.setValueAtTime(" & newT + MIDIevents(Index).me_mSecs_length & ", 0);" & vbCrLf
                    ''ttemp = ttemp & "brcoCO.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    KeyIndexIndex = KeyIndexIndex + 1
                    t2 = (20 + Int((newT + (MIDIevents(Index).me_mSecs_length * 0.95)) * 1000) / 1000)
                    If t2 = 20 + MIDIevents(Index).me_posTime Then
                        t2 = t2 + 0.001 'to prevent the third value being the same as the 2nd.
                    End If
                    ttemp = ttemp & "opac.setValueAtTime(" & t2 & ",[100,100]);" & vbCrLf
                    ttemp = ttemp & "opac.setInterpolationTypeAtKey(" & KeyIndexIndex & ",KeyframeInterpolationType.LINEAR);" & vbCrLf


                    My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, True)

                End If

            End If
            ProgressBar1.Value = Index
        Next
        ' ttemp = m & ttemp & "}"


        'ADD LIGHTS
        ''Note:  Array Lights(,) '0=name,1=Intensity,2=startX,3=startY, 4=startZ,5=endX,6=endY,7=endZ,8=coneangle,9 POIstartX,10 POIstartY,11 POIstartZ,12 POIendX,13 POIendY,14 POIendZ
        Dim Lights(,) = { _
        {"bottom 3rd", 180, 7500, ScreenY * (5 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"mid 3rd", 660, 7500, ScreenY * (2 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"top 3rd", 180, 7500, ScreenY * (-1 / 4), -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}, _
    {"make ambient", 13, 7500, 11000, -4500, 7500, 11000, -4500, 75, -4000, ScreenY + 200, 0, ScreenX + 5000, ScreenY + 200, 0}}

        ''NOTE - NEED TO ADD CODE FOR THE ABOVE



        'ADD standard Cameras

        ''Note:  Array Cameras(,) '0=name,1=zoom,2=startX,3=startY, 4=startZ,5=endX,6=endY,7=endZ,8=orientX,9=orientY,10=orientZ
        Dim cameras(,) = { _
        {"Whole image", 270000, ScreenX / 2, ScreenY / 2, -300000, ScreenX / 2, ScreenY / 2, -300000, 0, 0, 0}, _
        {"top third", 2200, 0, ScreenY * (1 / 6), -1100, ScreenX, ScreenY * (1 / 6), -1100, 0, 0, 0}, _
        {"mid third", 2200, 0, ScreenY * (3 / 6), -1100, ScreenX, ScreenY * (3 / 6), -1100, 0, 0, 0}, _
        {"low third", 2200, 0, ScreenY * (5 / 6), -1100, ScreenX, ScreenY * (5 / 6), -1100, 0, 0, 0}, _
        {"mid.low angle", 1100, 0, ScreenY * (3 / 6), -450, ScreenX, ScreenY * (3 / 6), -450, 0, 20, 90}, _
{"top.low angle", 1100, 0, ScreenY * (1 / 6), -450, ScreenX, ScreenY * (1 / 6), -450, 0, 20, 90}, _
{"low.low angle", 1100, 0, ScreenY * (5 / 6), -450, ScreenX, ScreenY * (5 / 6), -450, 0, 20, 90} _
}

        m = ""
        For f = 0 To UBound(cameras)
            m = m & "cam2 = comp.layers.addCamera(""" & cameras(f, 0) & """,[25,250]);" & vbCrLf
            m = m & "cam2.inPoint = 00;" & vbCrLf
            m = m & "cam2.outPoint =" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
            m = m & "p1= cam2.transform(""position"")" & vbCrLf
            m = m & "p1.setValueAtTime(0,[" & cameras(f, 2) & "," & cameras(f, 3) & "," & cameras(f, 4) & "]);" & vbCrLf
            m = m & "p1.setValueAtTime(" & HightestTrackTime & ",[" & cameras(f, 5) & "," & cameras(f, 6) & "," & cameras(f, 7) & "]);" & vbCrLf
            '        m = m & "cam2.property(""position"").setValue([" & 0 & "," & ScreenY * (1 / 6) & ",-1100]);" & vbCrLf
            'need point of interest
            'm = m & "cam1.property(""anchorPoint"").setValue([0, 0, 0]);" & vbCrLf
            m = m & "cam2.property(""zoom"").setValue(" & cameras(f, 1) & ");" & vbCrLf
            m = m & "cam2.autoOrient = AutoOrientType.NO_AUTO_ORIENT;" & vbCrLf
            m = m & "my3=cam2.transform(""orientation"");" & vbCrLf
            m = m & "my3.setValueAtTime(0,[" & cameras(f, 8) & "," & cameras(f, 9) & "," & cameras(f, 10) & "]);" & vbCrLf
            'm = m & "my3.setValueAtTime(12,[0,0,0]);" & vbCrLf

            'Add Markers to the first Camera only
            If f = 0 Then
                m = m & "var myMarker = new MarkerValue(""demo marker"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(2, myMarker);" & vbCrLf
                m = m & "var myMarker = new MarkerValue(""Fade down"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(11.4, myMarker);" & vbCrLf
                m = m & "var myMarker = new MarkerValue(""Fade it"");" & vbCrLf & "cam2.property(""Marker"").setValueAtTime(15, myMarker);" & vbCrLf
            End If
        Next

        If 2 = 3 Then
            'Add CAMERA which has the POI as the current note (works best for monophonic files)
            m = m & "cam2 = comp.layers.addCamera(""" & "Roving POI" & """,[25,250]);" & vbCrLf
            m = m & "cam2.inPoint = 00;" & vbCrLf
            m = m & "cam2.outPoint =" & Int(1 + HightestTrackTime) * CInt(TextBox2.Text) & vbCrLf
            m = m & "p1= cam2.transform(""position"")" & vbCrLf
            m = m & "p1.setValueAtTime(0,[" & ScreenX * (0 / 6) & "," & ScreenY * (3 / 6) & "," & -10000 & "]);" & vbCrLf
            m = m & "p1.setValueAtTime(" & HightestTrackTime & ",[" & ScreenX * (0 / 6) & "," & ScreenX * (6 / 6) & "," & -10000 & "]);" & vbCrLf
            '       m = m & "cam1.property(""anchorPoint"").setValue([0, 0, 0]);" & vbCrLf
            m = m & "cam2.property(""zoom"").setValue(" & 1100 & ");" & vbCrLf
            m = m & "cam2.autoOrient = AutoOrientType.CAMERA_OR_POINT_OF_INTEREST;" & vbCrLf

            'add all the POI changes.
            m = m & "my3=cam2.pointOfInterest;" & vbCrLf
            For Index = 0 To MIDIevents.Count - 1
                If MIDIevents(Index).me_note <> "" Then
                    m = m & "my3.setValueAtTime(" & MIDIevents(Index).me_posTime & ",[" & MIDIevents(Index).me_posX & "," & MIDIevents(Index).me_posY & "," & MIDIevents(Index).me_posZ & "]);" & vbCrLf
                End If
            Next
        End If






        My.Computer.FileSystem.WriteAllText(MyOutputfile, m & vbCrLf & "}", True)

        ''My.Computer.FileSystem.WriteAllText("C:\Test.txt", String.Empty, False)



h:
        'IntResult = 0
        'Try
        ' My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, False)
        'Catch ex As Exception
        'IntResult = MsgBox(ex.Message, MsgBoxStyle.RetryCancel)
        'End Try
        'If IntResult = DialogResult.Retry Then
        ''Else : MsgBox(IntResult)
        'GoTo h
        'End If
        ProgressBar1.Value = 0
        SaveAEscript5 = True

    End Function
    Function SaveAEscript2()
        Dim ttemp = ""
        Dim IntResult = 0
        Dim fflag = 0

        MyOutputfile = GetjsxOutputfile(".jsx")

        Dim m As String = ""
        Dim x As Integer
        Dim xn As String = "0000"
        Dim yn As String = "0000"


        'Finding out about the distribution of Notes and Channels
        Dim Index As Integer
        ' Dim Usage(128, 16) As Boolean


        Dim chanUsed(16, 4)
        ' 1= flag(is the channel used), 2=lowest Note on channel, 3=highest note on channel, 4= POINTER reference

        Dim pointerReference As Integer = 1
        ' Dim HiLoUsed(16, 3) As Integer
        For Index = 0 To 16
            chanUsed(Index, 1) = 0
            chanUsed(Index, 2) = 128
            chanUsed(Index, 3) = 0
            chanUsed(Index, 4) = 0
        Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                'Usage(MIDIevents(Index).me_note, MIDIevents(Index).me_Midi_Channel) = True
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 2)) > CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                If CInt(chanUsed(MIDIevents(Index).me_Midi_Channel, 3)) < CInt(MIDIevents(Index).me_note) Then
                    chanUsed(MIDIevents(Index).me_Midi_Channel, 3) = MIDIevents(Index).me_note
                End If
                'If MIDIevents(Index).me_Midi_Channel And MIDIevents(Index).me_note > 100 Then MsgBox(MIDIevents(Index).me_note)
                chanUsed(MIDIevents(Index).me_Midi_Channel, 1) = 1
                If chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = 0 Then chanUsed(MIDIevents(Index).me_Midi_Channel, 4) = pointerReference : pointerReference = pointerReference + 1
            End If
        Next
        '

        'what is the lowest and highest notes on any channel?
        ' How many channels are actually used. Assign each one a POINTER number

        'Dim loNote = 127
        'Dim hiNote = 0

        'Dim chanUsedI As Integer = 0
        'For x = 0 To 15
        'If loNote > HiLoUsed(x, 2) Then
        'loNote = HiLoUsed(x, 2)
        'End If
        'If hiNote < HiLoUsed(x, 1) Then
        'hiNote = HiLoUsed(x, 1)
        'End If
        '   Next
        'For x = 0 To 15
        'chanUsed(y, 2)=HiL
        'Next
        ' For x = 0 To 127
        'For y = 0 To 15
        'If Usage(x, y) = True Then
        'chanUsed(y, 1) = True
        ' chanUsed(y, 4) = pointerReference : pointerReference = pointerReference + 1
        ' Exit For
        'End If

        'Next
        'Next

        ''''''''''''''''''''''''''''''''''''

        m = m & "{" & vbCrLf
        m = m & "comp = app.project.activeItem;" & vbCrLf
        'ADD ONE SOLID
        m = m & "var layer1 = comp.layers.addSolid([0.5,0,0], """ & MyMidi & """,200,200, 1," & HightestTrackTime + 10 & ");" & vbCrLf
        m = m & "opac = layer1.property(""opacity"");" & vbCrLf
        m = m & "opac.setValueAtTime(0,[0]);" & vbCrLf
        m = m & "opac.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf

        'Create all the POINTER CONTROLS
        Dim controlname As String = ""
        For x = 0 To 15
            If chanUsed(x, 1) = 1 Then
                controlname = "Ch:" & CStr(x) & " Note range: " & chanUsed(x, 2) & " to " & chanUsed(x, 3) & " ptr:" & chanUsed(x, 4)
                m = m & "var ppoint1 = layer1.Effects.addProperty(""ADBE Point Control""); " & vbCrLf
                m = m & "ppoint1.name = """ & controlname & """" & ";" & vbCrLf
            End If
        Next

        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf

        Dim Vel2AE

        Dim newF As Double
        Dim newT As Double
        ttemp = ""
        ProgressBar1.Maximum = MIDIevents.Count
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next

        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = Trim(Str(MIDIevents(Index).me_note))
                ' xn = xn.Substring(Len(xn) - 3, 3)
                ' yn = 1 + Trim(Str(MIDIevents(Index).me_Midi_Channel))

                yn = chanUsed(MIDIevents(Index).me_Midi_Channel, 4)

                Vel2AE = Trim(MIDIevents(Index).me_velocity)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0
                'Adjust the event TIME to only occur at FRAMES.
                newF = (MIDIevents(Index).me_Secs_into_Track) / (1 / CInt(TextBox2.Text))
                If (newF - Int(newF)) > 0.5 Then
                    newF = Int(newF) + 1
                Else
                    newF = Int(newF)
                End If

                'If there is already an offset, then adjust the Frame
                newF = newF - YNoffset(yn) : YNoffset(yn) = 0
                'If there is already an entry for that Frame on that Channel, then offset the Frame.
                If newF = LastYN(yn) Then newF = newF + 1 : YNoffset(yn) = YNoffset(yn) + 1
                LastYN(yn) = newF
                ' ListBox1.Items.Add(yn & ":" & YNoffset(yn) & ":" & newF)
                newT = newF * (1 / CInt(TextBox2.Text))

                ttemp = ttemp & "layer1.Effects(" & yn & ").property(1)" & ".setValueAtTime(" & newT & ",[" & xn & "," & Vel2AE & "]);" & vbCrLf
                ttemp = ttemp & "layer1.Effects(" & yn & ").property(1)" & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.LINEAR,KeyframeInterpolationType.HOLD);" & vbCrLf


                'If MIDIevents(Index).me_velocity = 0 Then
                'ttemp = ttemp & "" & xn & "_" & yn & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.LINEAR,KeyframeInterpolationType.HOLD);" & vbCrLf
                'Else
                '    ttemp = ttemp & "myi" & xn & "_" & yn & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD,KeyframeInterpolationType.HOLD);" & vbCrLf
                'End If
            End If
            ProgressBar1.Value = Index

        Next
        ttemp = m & ttemp & "}"


h:
        IntResult = 0
        Try
            My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, False)
        Catch ex As Exception
            IntResult = MsgBox(ex.Message, MsgBoxStyle.RetryCancel)
        End Try
        If IntResult = DialogResult.Retry Then
            'Else : MsgBox(IntResult)
            GoTo h
        End If
        ProgressBar1.Value = 0
        SaveAEscript2 = True

    End Function
    Function SaveAEscript()
        Dim ttemp = ""
        Dim ttemp2 = ""
        Dim IntResult = 0
        Dim fflag = 0


        MyOutputfile = GetjsxOutputfile(".jsx")

        Dim m As String = ""
        Dim x As Integer
        Dim y As Integer
        Dim xn As String = "0000"
        Dim yn As String = "0000"


        'Finding out about the distribution of Notes and Channels
        Dim Index As Integer
        Dim Usage(128, 16) As Boolean
        Dim HiLoUsed(16, 3) As Integer
        For Index = 0 To 16
            HiLoUsed(Index, 2) = 128
        Next
        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                Usage(MIDIevents(Index).me_note, MIDIevents(Index).me_Midi_Channel) = True
                If HiLoUsed(MIDIevents(Index).me_Midi_Channel, 1) < MIDIevents(Index).me_note Then
                    HiLoUsed(MIDIevents(Index).me_Midi_Channel, 1) = MIDIevents(Index).me_note
                End If
                If HiLoUsed(MIDIevents(Index).me_Midi_Channel, 2) > MIDIevents(Index).me_note Then
                    HiLoUsed(MIDIevents(Index).me_Midi_Channel, 2) = MIDIevents(Index).me_note
                End If
                HiLoUsed(MIDIevents(Index).me_Midi_Channel, 3) = 1
            End If
        Next
        'what is the lowest and highest notes on any channel?
        Dim loNote = 127
        Dim hiNote = 0
        For x = 0 To 15
            If loNote > HiLoUsed(x, 2) Then
                loNote = HiLoUsed(x, 2)
            End If
            If hiNote < HiLoUsed(x, 1) Then
                hiNote = HiLoUsed(x, 1)
            End If
        Next
        ' How many channels are actually used
        Dim chanUsed(16)
        Dim chanUsedI As Integer = 0
        For x = 0 To 127
            For y = 0 To 15
                If Usage(x, y) = True Then chanUsed(y) = True
            Next
        Next
        For y = 0 To 15
            If chanUsed(y) = True Then chanUsedI = chanUsedI + 1
        Next
        ' MsgBox(chanUsedI)
        'if RadioButton1 then
        'screen width= 1280
        'screen height=720
        ' x * 10,(y * 40) + 30
        'max x=(hinote - lonote), max y=chanUsed
        '
        Dim xi As Integer = 0
        Dim yi As Integer = 0
        Dim xf As Integer = 0
        Dim yf As Integer = 0
        yf = 720 / chanUsedI
        xf = 1280 / (2 + hiNote - loNote)


        m = m & "{" & vbCrLf
        m = m & "myComp = app.project.item(1);" & vbCrLf
        For x = 0 To 127
            xn = "0000" & Trim(Str(x))
            xn = xn.Substring(Len(xn) - 3, 3)
            yi = 0
            For y = 0 To 15
                If Usage(x, y) = True Then
                    yn = "0000" & Trim(Str(y))
                    yn = yn.Substring(Len(yn) - 3, 3)
                    m = m & "mySolid" & xn & "_" & yn & " = myComp.layers.addSolid([1.0,1.0,0], ""n_" & xn & "_c_" & yn & """, " & xf & ", " & yf & ", 1," & HightestTrackTime + 10 & ");" & vbCrLf
                    m = m & "myPosition = mySolid" & xn & "_" & yn & ".property(""position"");" & vbCrLf
                    m = m & "myPosition.setValueAtTime(0,[" & ((x - loNote) * xf) + (xf / 2) & "," & (yi * yf) + (yf / 2) & "]);" & vbCrLf
                    m = m & "myi" & xn & "_" & yn & " = mySolid" & xn & "_" & yn & ".property(""opacity"");" & vbCrLf
                    m = m & "myi" & xn & "_" & yn & ".setValueAtTime(0,[100]);" & vbCrLf
                    m = m & "myi" & xn & "_" & yn & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD);" & vbCrLf
                    '  m = m & "myi" & xn & "_" & yn & ".setValueAtTime(12,[8]);" & vbCrLf
                End If
                If chanUsed(y) = True Then yi = yi + 1
            Next
        Next
        ' m = m & "}" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf
        m = m & "" & vbCrLf

        Dim Vel2AE
        ttemp = ""
        ProgressBar1.Maximum = MIDIevents.Count
        Dim newF As Double
        Dim newT As Double
        Dim LastYN(16) As Integer : For Index = 0 To 16 : LastYN(Index) = -1 : Next
        Dim YNoffset(16) As Integer : For Index = 0 To 16 : YNoffset(Index) = 0 : Next


        For Index = 0 To MIDIevents.Count - 1
            If MIDIevents(Index).me_note <> "" Then
                xn = "0000" & Trim(Str(MIDIevents(Index).me_note))
                xn = xn.Substring(Len(xn) - 3, 3)
                yn = "0000" & Trim(Str(MIDIevents(Index).me_Midi_Channel))
                yn = yn.Substring(Len(yn) - 3, 3)
                Vel2AE = 100 - ((MIDIevents(Index).me_velocity / 128) * 100)
                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0
                'Adjust the event TIME to only occur at FRAMES.
                newF = (MIDIevents(Index).me_Secs_into_Track) / (1 / CInt(TextBox2.Text))
                If (newF - Int(newF)) > 0.5 Then
                    newF = Int(newF) + 1
                Else
                    newF = Int(newF)
                End If

                'If there is already an offset, then adjust the Frame
                newF = newF - YNoffset(yn) : YNoffset(yn) = 0
                'If there is already an entry for that Frame on that Channel, then offset the Frame.
                If newF = LastYN(yn) Then newF = newF + 1 : YNoffset(yn) = YNoffset(yn) + 1
                LastYN(yn) = newF
                ''ListBox1.Items.Add(yn & ":" & YNoffset(yn) & ":" & newF)
                newT = newF * (1 / CInt(TextBox2.Text))


                If MIDIevents(Index).me_type0 = 5 Then Vel2AE = 0
                ttemp = ttemp & "myi" & xn & "_" & yn & ".setValueAtTime(" & newT & ",[" & Vel2AE & "]);" & vbCrLf
                If MIDIevents(Index).me_velocity = 0 Then
                    ttemp = ttemp & "myi" & xn & "_" & yn & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.LINEAR,KeyframeInterpolationType.HOLD);" & vbCrLf
                Else
                    ttemp = ttemp & "myi" & xn & "_" & yn & ".setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD,KeyframeInterpolationType.HOLD);" & vbCrLf
                End If
            End If
            ProgressBar1.Value = Index
        Next
        ttemp = m & ttemp & "}"


h:
        IntResult = 0
        Try
            My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, False)
        Catch ex As Exception
            IntResult = MsgBox(ex.Message, MsgBoxStyle.RetryCancel)
        End Try
        If IntResult = DialogResult.Retry Then
            'Else : MsgBox(IntResult)
            GoTo h
        End If
        ProgressBar1.Value = 0
        SaveAEscript = True
    End Function


    Function SaveCSV()
        Dim ttemp = ""
        Dim ttemp2 = ""
        Dim IntResult = 0
        Dim fflag = 0
        Dim nnow As String = CStr(Now())
        nnow = Replace(nnow, "/", "_")
        nnow = Replace(nnow, ":", "_")
        nnow = Replace(nnow, " ", "__")
        Dim a As Integer = InStrRev(MyFile, "\")
        Dim MyOutputFolder = MyFile.Substring(0, a)
        MyOutputfile = MyOutputFolder & MyFile.Substring(a, Len(MyFile) - a - 4) & "_" & nnow & ".csv"

        Dim FPS As Integer = CInt(TextBox1.Text)
        ttemp = ""
        ProgressBar1.Maximum = MIDIevents.Count
        Dim Index As Integer

        'ttemp = ttemp & ("Dtime, totalDtime, Ticks in tempo Periods, secs in Event,secs into Track,Current BPM," & _
        '  "BeatsPassed, TrackName, Instrument Name, Event, Event2, MidiChannel,Note, Velocity,Value1,Value2")

        'which Column headers to show
        If CheckBox25.Checked Then ttemp = ttemp & "FRAME,"
        If CheckBox4.Checked Then ttemp = ttemp & "Dtime,"
        If CheckBox5.Checked Then ttemp = ttemp & "TotalDtime,"
        If CheckBox6.Checked Then ttemp = ttemp & "Ticks in tempo Periods,"
        If CheckBox7.Checked Then ttemp = ttemp & "secs in Event,"
        If CheckBox8.Checked Then ttemp = ttemp & "secs into Track,"
        If CheckBox23.Checked Then ttemp = ttemp & "Duration of Note (secs),"
        If CheckBox9.Checked Then ttemp = ttemp & "Current BPM,"
        If CheckBox10.Checked Then ttemp = ttemp & "BeatsPassed,"
        If CheckBox26.Checked Then ttemp = ttemp & "Total_BeatsPassed,"
        If CheckBox12.Checked Then ttemp = ttemp & "TrackName,"
        If CheckBox3.Checked Then ttemp = ttemp & "Instrument Name,"
        If CheckBox13.Checked Then ttemp = ttemp & "Event,"
        If CheckBox11.Checked Then ttemp = ttemp & "Event2,"
        If CheckBox14.Checked Then ttemp = ttemp & "MidiChannel,"
        If CheckBox17.Checked Then ttemp = ttemp & "Note,"
        If CheckBox18.Checked Then ttemp = ttemp & "Velocity,"
        If CheckBox15.Checked Then ttemp = ttemp & "Value1,"
        If CheckBox16.Checked Then ttemp = ttemp & "Value2,"
        If CheckBox27.Checked Then ttemp = ttemp & "secs till next occurence of same note"

        ' If CheckBox4.Checked Then ttemp = ttemp & ","
        ttemp = ttemp & vbCrLf


        For Index = 0 To MIDIevents.Count - 1
            fflag = 0
            If ((MIDIevents(Index).me_type0 = 0) And (CheckBox1.Checked = True)) Then fflag = 1 ' show midifile and chunk data
            If ((MIDIevents(Index).me_type0 = 1) And (CheckBox21.Checked = True)) Then fflag = 1 ' show MetaCommands
            If ((MIDIevents(Index).me_type0 = 4) And (CheckBox2.Checked = True)) Then fflag = 1 ' show Controllers
            If (((MIDIevents(Index).me_type0 = 2) Or (MIDIevents(Index).me_type0 = 5)) And (CheckBox20.Checked = True)) Then
                fflag = 1 'standard events
                'ignore note offs, if required
                If ((MIDIevents(Index).me_velocity = 0) And (MIDIevents(Index).me_Event = "Note On")) _
                Or ((MIDIevents(Index).me_Event = "Note Off")) Then
                    If CheckBox29.Checked = False Then
                        fflag = 0
                    End If
                End If
            End If
            If fflag = 1 Then
                ttemp2 = ""

                'add FRAME number (based on time into the track and the user's chosen FPS)
                Dim tempSecs = MIDIevents(Index).me_Secs_into_Track
                Dim tempFrame = Convert.ToInt32(tempSecs * FPS)
                If CheckBox25.Checked Then ttemp2 = ttemp2 & (tempFrame) & ","

                If CheckBox4.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Delta_Ticks) & ","
                If CheckBox5.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Total_Delta_Ticks) & ","
                If CheckBox6.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Ticks_in_each_period) & ","
                If CheckBox7.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Secs_in_Event) & ","
                If CheckBox8.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Secs_into_Track) & ","
                If CheckBox23.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_mSecs_length) & ","
                If CheckBox9.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Current_BPM) & ","
                If CheckBox10.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Beats_Passed) & ","
                If CheckBox26.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Total_Beats_Passed) & ","

                If CheckBox12.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Trackname) & ","
                If CheckBox3.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_InstrumentName) & ","

                If CheckBox13.Checked Then
                    If (CheckBox19.Checked = True) And (MIDIevents(Index).me_velocity = 0) And (MIDIevents(Index).me_Event = "Note On") Then
                        ' Show MidiOn(VEL=0) as a NoteOff
                        ttemp2 = ttemp2 & "Note Off" & ","
                    Else
                        ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Event) & ","
                    End If

                End If



                If CheckBox11.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Event2) & ","
                If CheckBox14.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Midi_Channel) & ","


                'COMMENT for next time I update this. If there it not a Note, then there is no need to show the Note.
                'need to change following line to:
                ''If CheckBox17.Checked AND MIDIevents(Index).me_Event includes the string "Note", then showing them

                    If CheckBox17.Checked Then
                        If CheckBox22.Checked = True Then
                            ttemp2 = ttemp2 & rc(keys(MIDIevents(Index).me_note Mod 12)) & rc(Int(MIDIevents(Index).me_note / 12)) & ","
                        Else
                            ttemp2 = ttemp2 & rc(MIDIevents(Index).me_note) & ","
                        End If
                    End If




                    If CheckBox18.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_velocity) & ","
                    If CheckBox15.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_Value1) & ","
                    If CheckBox16.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_value2) & ","
                    If CheckBox27.Checked Then ttemp2 = ttemp2 & rc(MIDIevents(Index).me_secs_tillnextOccurence) & ","
                    If ttemp2 <> "" Then
                        ttemp = ttemp & ttemp2 & vbCrLf
                    End If
                    ProgressBar1.Value = Index
                End If

        Next



h:
        IntResult = 0
        Try
            My.Computer.FileSystem.WriteAllText(MyOutputfile, ttemp, False)
        Catch ex As Exception
            IntResult = MsgBox(ex.Message, MsgBoxStyle.RetryCancel)
        End Try
        If IntResult = DialogResult.Retry Then
            'Else : MsgBox(IntResult)
            GoTo h
        End If
        ProgressBar1.Value = 0
        SaveCSV = True
    End Function

    Function rc(astring)
        rc = Replace(astring, ",", ".")


    End Function
    Public Sub UpdateGeneralTab()
        Label6.Text = MyFile
        Label10.Text = MIDIevents.Count
        Label11.Text = CurrentTrackNum
        Label5.Text = HightestTrackTime
        Label34.Text = "Shortest Note: " & CStr(ShortestNote)
    End Sub
    Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.LostFocus
        If IsNumeric(TextBox1.Text) Then
            If CInt(TextBox1.Text) > 0 And CInt(TextBox1.Text) < 99 Then
            Else
                TextBox1.Text = 30
            End If
        Else
            TextBox1.Text = 30
        End If
    End Sub
    Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs)
        System.Diagnostics.Process.Start("http://www.tima.uk.com/midianal.htm")
    End Sub
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        SaveAEscript()
    End Sub
    Private Sub LinkLabel2_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs)
        System.Diagnostics.Process.Start("mailto://tim@tima.uk.com")
    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        SaveAEscript2()
    End Sub
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        SaveAEscript3()

    End Sub

    Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        SaveScript4()
    End Sub

    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
        SaveAEscript5()
    End Sub


    Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        SaveVRMLscript1()
    End Sub

    Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click
        SaveVRMLscript2()
    End Sub

    Private Sub RadioButton2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton2.CheckedChanged
        NumericUpDown1.Enabled = False
        TextBox8.Enabled = True
    End Sub

    Private Sub RadioButton3_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton3.CheckedChanged
        NumericUpDown1.Enabled = True
        TextBox8.Enabled = False
    End Sub

    Private Sub Button9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        ' Label35.Text = Str(1 / CDbl(TextBox7.Text)) & " ms"
    End Sub

    Private Sub Button10_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        ' Label36.Text = Str(1 / CDbl(TextBox9.Text))
    End Sub

    Private Sub AboutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        AboutBox1.Show()
    End Sub


  
    
   
    Private Sub Panel8_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Panel8.Paint

    End Sub
End Class
Public Class MIDIevent
    Public me_Delta_Ticks As String
    Public me_Total_Delta_Ticks As String
    Public me_Ticks_in_each_period As String
    Public me_Secs_in_Event As String
    Public me_Secs_into_Track As String
    Public me_Current_BPM As String
    Public me_Beats_Passed As String
    Public me_Total_Beats_Passed As String
    Public me_empty1 As String
    Public me_Trackname As String
    Public me_InstrumentName As String
    Public me_Event As String
    Public me_Event2 As String
    Public me_Midi_Channel As String
    Public me_Value1 As String
    Public me_note As String
    Public me_velocity As String
    Public me_value2 As String
    Public me_type0 As Integer
    Public me_mSecs_length As Double
    Public me_posX As Double
    Public me_posY As Double
    Public me_posZ As Double
    Public me_posTime As Double
    Public me_secs_tillnextOccurence As Double
    'Public me_ As String
End Class
Public Class MIDIeventCollection
    Inherits CollectionBase
    Public Sub Add(ByVal _MIDIevent As MIDIevent)
        List.Add(_MIDIevent)
    End Sub
    Default Public Overridable ReadOnly Property Item(ByVal index As Integer) As MIDIevent
        Get
            Return CType(Me.List(index), MIDIevent)
        End Get
    End Property
End Class
